diff options
Diffstat (limited to 'drivers')
168 files changed, 10928 insertions, 4715 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 7bdae47d6b91..4fb134d50da7 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -84,6 +84,8 @@ source "drivers/rtc/Kconfig" | |||
84 | 84 | ||
85 | source "drivers/dma/Kconfig" | 85 | source "drivers/dma/Kconfig" |
86 | 86 | ||
87 | source "drivers/dca/Kconfig" | ||
88 | |||
87 | source "drivers/auxdisplay/Kconfig" | 89 | source "drivers/auxdisplay/Kconfig" |
88 | 90 | ||
89 | source "drivers/kvm/Kconfig" | 91 | source "drivers/kvm/Kconfig" |
diff --git a/drivers/Makefile b/drivers/Makefile index a168eacdcd9c..174c27eb4430 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -85,6 +85,7 @@ obj-$(CONFIG_CRYPTO) += crypto/ | |||
85 | obj-$(CONFIG_SUPERH) += sh/ | 85 | obj-$(CONFIG_SUPERH) += sh/ |
86 | obj-$(CONFIG_GENERIC_TIME) += clocksource/ | 86 | obj-$(CONFIG_GENERIC_TIME) += clocksource/ |
87 | obj-$(CONFIG_DMA_ENGINE) += dma/ | 87 | obj-$(CONFIG_DMA_ENGINE) += dma/ |
88 | obj-$(CONFIG_DCA) += dca/ | ||
88 | obj-$(CONFIG_HID) += hid/ | 89 | obj-$(CONFIG_HID) += hid/ |
89 | obj-$(CONFIG_PPC_PS3) += ps3/ | 90 | obj-$(CONFIG_PPC_PS3) += ps3/ |
90 | obj-$(CONFIG_OF) += of/ | 91 | obj-$(CONFIG_OF) += of/ |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ba62d534f32b..9fbb39cd0f58 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -3238,7 +3238,7 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) | |||
3238 | 3238 | ||
3239 | /** | 3239 | /** |
3240 | * ata_scsi_media_change_notify - send media change event | 3240 | * ata_scsi_media_change_notify - send media change event |
3241 | * @atadev: Pointer to the disk device with media change event | 3241 | * @dev: Pointer to the disk device with media change event |
3242 | * | 3242 | * |
3243 | * Tell the block layer to send a media change notification | 3243 | * Tell the block layer to send a media change notification |
3244 | * event. | 3244 | * event. |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 7a1390cd6aad..c41d0728efe2 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -238,7 +238,7 @@ store_mem_state(struct sys_device *dev, const char *buf, size_t count) | |||
238 | mem = container_of(dev, struct memory_block, sysdev); | 238 | mem = container_of(dev, struct memory_block, sysdev); |
239 | phys_section_nr = mem->phys_index; | 239 | phys_section_nr = mem->phys_index; |
240 | 240 | ||
241 | if (!valid_section_nr(phys_section_nr)) | 241 | if (!present_section_nr(phys_section_nr)) |
242 | goto out; | 242 | goto out; |
243 | 243 | ||
244 | if (!strncmp(buf, "online", min((int)count, 6))) | 244 | if (!strncmp(buf, "online", min((int)count, 6))) |
@@ -418,7 +418,7 @@ int register_new_memory(struct mem_section *section) | |||
418 | 418 | ||
419 | int unregister_memory_section(struct mem_section *section) | 419 | int unregister_memory_section(struct mem_section *section) |
420 | { | 420 | { |
421 | if (!valid_section(section)) | 421 | if (!present_section(section)) |
422 | return -EINVAL; | 422 | return -EINVAL; |
423 | 423 | ||
424 | return remove_memory_block(0, section, 0); | 424 | return remove_memory_block(0, section, 0); |
@@ -443,7 +443,7 @@ int __init memory_dev_init(void) | |||
443 | * during boot and have been initialized | 443 | * during boot and have been initialized |
444 | */ | 444 | */ |
445 | for (i = 0; i < NR_MEM_SECTIONS; i++) { | 445 | for (i = 0; i < NR_MEM_SECTIONS; i++) { |
446 | if (!valid_section_nr(i)) | 446 | if (!present_section_nr(i)) |
447 | continue; | 447 | continue; |
448 | err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); | 448 | err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); |
449 | if (!ret) | 449 | if (!ret) |
diff --git a/drivers/base/node.c b/drivers/base/node.c index cae346ef1b20..88eeed72b5d6 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/topology.h> | 12 | #include <linux/topology.h> |
13 | #include <linux/nodemask.h> | 13 | #include <linux/nodemask.h> |
14 | #include <linux/cpu.h> | 14 | #include <linux/cpu.h> |
15 | #include <linux/device.h> | ||
15 | 16 | ||
16 | static struct sysdev_class node_class = { | 17 | static struct sysdev_class node_class = { |
17 | set_kset_name("node"), | 18 | set_kset_name("node"), |
@@ -232,8 +233,96 @@ void unregister_one_node(int nid) | |||
232 | unregister_node(&node_devices[nid]); | 233 | unregister_node(&node_devices[nid]); |
233 | } | 234 | } |
234 | 235 | ||
236 | /* | ||
237 | * node states attributes | ||
238 | */ | ||
239 | |||
240 | static ssize_t print_nodes_state(enum node_states state, char *buf) | ||
241 | { | ||
242 | int n; | ||
243 | |||
244 | n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]); | ||
245 | if (n > 0 && PAGE_SIZE > n + 1) { | ||
246 | *(buf + n++) = '\n'; | ||
247 | *(buf + n++) = '\0'; | ||
248 | } | ||
249 | return n; | ||
250 | } | ||
251 | |||
252 | static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf) | ||
253 | { | ||
254 | return print_nodes_state(N_POSSIBLE, buf); | ||
255 | } | ||
256 | |||
257 | static ssize_t print_nodes_online(struct sysdev_class *class, char *buf) | ||
258 | { | ||
259 | return print_nodes_state(N_ONLINE, buf); | ||
260 | } | ||
261 | |||
262 | static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class, | ||
263 | char *buf) | ||
264 | { | ||
265 | return print_nodes_state(N_NORMAL_MEMORY, buf); | ||
266 | } | ||
267 | |||
268 | static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf) | ||
269 | { | ||
270 | return print_nodes_state(N_CPU, buf); | ||
271 | } | ||
272 | |||
273 | static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL); | ||
274 | static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL); | ||
275 | static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory, | ||
276 | NULL); | ||
277 | static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL); | ||
278 | |||
279 | #ifdef CONFIG_HIGHMEM | ||
280 | static ssize_t print_nodes_has_high_memory(struct sysdev_class *class, | ||
281 | char *buf) | ||
282 | { | ||
283 | return print_nodes_state(N_HIGH_MEMORY, buf); | ||
284 | } | ||
285 | |||
286 | static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory, | ||
287 | NULL); | ||
288 | #endif | ||
289 | |||
290 | struct sysdev_class_attribute *node_state_attr[] = { | ||
291 | &attr_possible, | ||
292 | &attr_online, | ||
293 | &attr_has_normal_memory, | ||
294 | #ifdef CONFIG_HIGHMEM | ||
295 | &attr_has_high_memory, | ||
296 | #endif | ||
297 | &attr_has_cpu, | ||
298 | }; | ||
299 | |||
300 | static int node_states_init(void) | ||
301 | { | ||
302 | int i; | ||
303 | int err = 0; | ||
304 | |||
305 | for (i = 0; i < NR_NODE_STATES; i++) { | ||
306 | int ret; | ||
307 | ret = sysdev_class_create_file(&node_class, node_state_attr[i]); | ||
308 | if (!err) | ||
309 | err = ret; | ||
310 | } | ||
311 | return err; | ||
312 | } | ||
313 | |||
235 | static int __init register_node_type(void) | 314 | static int __init register_node_type(void) |
236 | { | 315 | { |
237 | return sysdev_class_register(&node_class); | 316 | int ret; |
317 | |||
318 | ret = sysdev_class_register(&node_class); | ||
319 | if (!ret) | ||
320 | ret = node_states_init(); | ||
321 | |||
322 | /* | ||
323 | * Note: we're not going to unregister the node class if we fail | ||
324 | * to register the node state class attribute files. | ||
325 | */ | ||
326 | return ret; | ||
238 | } | 327 | } |
239 | postcore_initcall(register_node_type); | 328 | postcore_initcall(register_node_type); |
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b9233a06934c..e5a051577a5e 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -204,14 +204,13 @@ lo_do_transfer(struct loop_device *lo, int cmd, | |||
204 | * do_lo_send_aops - helper for writing data to a loop device | 204 | * do_lo_send_aops - helper for writing data to a loop device |
205 | * | 205 | * |
206 | * This is the fast version for backing filesystems which implement the address | 206 | * This is the fast version for backing filesystems which implement the address |
207 | * space operations prepare_write and commit_write. | 207 | * space operations write_begin and write_end. |
208 | */ | 208 | */ |
209 | static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, | 209 | static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, |
210 | int bsize, loff_t pos, struct page *page) | 210 | int bsize, loff_t pos, struct page *unused) |
211 | { | 211 | { |
212 | struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ | 212 | struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ |
213 | struct address_space *mapping = file->f_mapping; | 213 | struct address_space *mapping = file->f_mapping; |
214 | const struct address_space_operations *aops = mapping->a_ops; | ||
215 | pgoff_t index; | 214 | pgoff_t index; |
216 | unsigned offset, bv_offs; | 215 | unsigned offset, bv_offs; |
217 | int len, ret; | 216 | int len, ret; |
@@ -223,63 +222,45 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, | |||
223 | len = bvec->bv_len; | 222 | len = bvec->bv_len; |
224 | while (len > 0) { | 223 | while (len > 0) { |
225 | sector_t IV; | 224 | sector_t IV; |
226 | unsigned size; | 225 | unsigned size, copied; |
227 | int transfer_result; | 226 | int transfer_result; |
227 | struct page *page; | ||
228 | void *fsdata; | ||
228 | 229 | ||
229 | IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); | 230 | IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); |
230 | size = PAGE_CACHE_SIZE - offset; | 231 | size = PAGE_CACHE_SIZE - offset; |
231 | if (size > len) | 232 | if (size > len) |
232 | size = len; | 233 | size = len; |
233 | page = grab_cache_page(mapping, index); | 234 | |
234 | if (unlikely(!page)) | 235 | ret = pagecache_write_begin(file, mapping, pos, size, 0, |
236 | &page, &fsdata); | ||
237 | if (ret) | ||
235 | goto fail; | 238 | goto fail; |
236 | ret = aops->prepare_write(file, page, offset, | 239 | |
237 | offset + size); | ||
238 | if (unlikely(ret)) { | ||
239 | if (ret == AOP_TRUNCATED_PAGE) { | ||
240 | page_cache_release(page); | ||
241 | continue; | ||
242 | } | ||
243 | goto unlock; | ||
244 | } | ||
245 | transfer_result = lo_do_transfer(lo, WRITE, page, offset, | 240 | transfer_result = lo_do_transfer(lo, WRITE, page, offset, |
246 | bvec->bv_page, bv_offs, size, IV); | 241 | bvec->bv_page, bv_offs, size, IV); |
247 | if (unlikely(transfer_result)) { | 242 | copied = size; |
248 | /* | ||
249 | * The transfer failed, but we still write the data to | ||
250 | * keep prepare/commit calls balanced. | ||
251 | */ | ||
252 | printk(KERN_ERR "loop: transfer error block %llu\n", | ||
253 | (unsigned long long)index); | ||
254 | zero_user_page(page, offset, size, KM_USER0); | ||
255 | } | ||
256 | flush_dcache_page(page); | ||
257 | ret = aops->commit_write(file, page, offset, | ||
258 | offset + size); | ||
259 | if (unlikely(ret)) { | ||
260 | if (ret == AOP_TRUNCATED_PAGE) { | ||
261 | page_cache_release(page); | ||
262 | continue; | ||
263 | } | ||
264 | goto unlock; | ||
265 | } | ||
266 | if (unlikely(transfer_result)) | 243 | if (unlikely(transfer_result)) |
267 | goto unlock; | 244 | copied = 0; |
268 | bv_offs += size; | 245 | |
269 | len -= size; | 246 | ret = pagecache_write_end(file, mapping, pos, size, copied, |
247 | page, fsdata); | ||
248 | if (ret < 0 || ret != copied) | ||
249 | goto fail; | ||
250 | |||
251 | if (unlikely(transfer_result)) | ||
252 | goto fail; | ||
253 | |||
254 | bv_offs += copied; | ||
255 | len -= copied; | ||
270 | offset = 0; | 256 | offset = 0; |
271 | index++; | 257 | index++; |
272 | pos += size; | 258 | pos += copied; |
273 | unlock_page(page); | ||
274 | page_cache_release(page); | ||
275 | } | 259 | } |
276 | ret = 0; | 260 | ret = 0; |
277 | out: | 261 | out: |
278 | mutex_unlock(&mapping->host->i_mutex); | 262 | mutex_unlock(&mapping->host->i_mutex); |
279 | return ret; | 263 | return ret; |
280 | unlock: | ||
281 | unlock_page(page); | ||
282 | page_cache_release(page); | ||
283 | fail: | 264 | fail: |
284 | ret = -1; | 265 | ret = -1; |
285 | goto out; | 266 | goto out; |
@@ -313,7 +294,7 @@ static int __do_lo_send_write(struct file *file, | |||
313 | * do_lo_send_direct_write - helper for writing data to a loop device | 294 | * do_lo_send_direct_write - helper for writing data to a loop device |
314 | * | 295 | * |
315 | * This is the fast, non-transforming version for backing filesystems which do | 296 | * This is the fast, non-transforming version for backing filesystems which do |
316 | * not implement the address space operations prepare_write and commit_write. | 297 | * not implement the address space operations write_begin and write_end. |
317 | * It uses the write file operation which should be present on all writeable | 298 | * It uses the write file operation which should be present on all writeable |
318 | * filesystems. | 299 | * filesystems. |
319 | */ | 300 | */ |
@@ -332,7 +313,7 @@ static int do_lo_send_direct_write(struct loop_device *lo, | |||
332 | * do_lo_send_write - helper for writing data to a loop device | 313 | * do_lo_send_write - helper for writing data to a loop device |
333 | * | 314 | * |
334 | * This is the slow, transforming version for filesystems which do not | 315 | * This is the slow, transforming version for filesystems which do not |
335 | * implement the address space operations prepare_write and commit_write. It | 316 | * implement the address space operations write_begin and write_end. It |
336 | * uses the write file operation which should be present on all writeable | 317 | * uses the write file operation which should be present on all writeable |
337 | * filesystems. | 318 | * filesystems. |
338 | * | 319 | * |
@@ -780,7 +761,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
780 | */ | 761 | */ |
781 | if (!file->f_op->splice_read) | 762 | if (!file->f_op->splice_read) |
782 | goto out_putf; | 763 | goto out_putf; |
783 | if (aops->prepare_write && aops->commit_write) | 764 | if (aops->prepare_write || aops->write_begin) |
784 | lo_flags |= LO_FLAGS_USE_AOPS; | 765 | lo_flags |= LO_FLAGS_USE_AOPS; |
785 | if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) | 766 | if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) |
786 | lo_flags |= LO_FLAGS_READ_ONLY; | 767 | lo_flags |= LO_FLAGS_READ_ONLY; |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index b391776e5bf3..f6f8c03047fa 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -896,10 +896,6 @@ config GPIO_TB0219 | |||
896 | depends on TANBAC_TB022X | 896 | depends on TANBAC_TB022X |
897 | select GPIO_VR41XX | 897 | select GPIO_VR41XX |
898 | 898 | ||
899 | source "drivers/char/agp/Kconfig" | ||
900 | |||
901 | source "drivers/char/drm/Kconfig" | ||
902 | |||
903 | source "drivers/char/pcmcia/Kconfig" | 899 | source "drivers/char/pcmcia/Kconfig" |
904 | 900 | ||
905 | config MWAVE | 901 | config MWAVE |
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 713533d8a86e..f22c253bc09f 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
@@ -1,4 +1,4 @@ | |||
1 | config AGP | 1 | menuconfig AGP |
2 | tristate "/dev/agpgart (AGP Support)" | 2 | tristate "/dev/agpgart (AGP Support)" |
3 | depends on ALPHA || IA64 || PARISC || PPC || X86 | 3 | depends on ALPHA || IA64 || PARISC || PPC || X86 |
4 | depends on PCI | 4 | depends on PCI |
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 0b7ffa5191c6..ba3058dd39a7 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig | |||
@@ -4,7 +4,7 @@ | |||
4 | # This driver provides support for the | 4 | # This driver provides support for the |
5 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. | 5 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. |
6 | # | 6 | # |
7 | config DRM | 7 | menuconfig DRM |
8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" | 8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" |
9 | depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG | 9 | depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG |
10 | help | 10 | help |
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index f89e57665b64..2b2407ee490e 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c | |||
@@ -144,8 +144,8 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) | |||
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
146 | 146 | ||
147 | int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence, | 147 | static int radeon_driver_vblank_do_wait(struct drm_device * dev, |
148 | int crtc) | 148 | unsigned int *sequence, int crtc) |
149 | { | 149 | { |
150 | drm_radeon_private_t *dev_priv = | 150 | drm_radeon_private_t *dev_priv = |
151 | (drm_radeon_private_t *) dev->dev_private; | 151 | (drm_radeon_private_t *) dev->dev_private; |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index bbee97ff355f..64551ab6be03 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -625,65 +625,10 @@ static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, | |||
625 | return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); | 625 | return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); |
626 | } | 626 | } |
627 | 627 | ||
628 | #ifdef CONFIG_MMU | ||
629 | /* | ||
630 | * For fun, we are using the MMU for this. | ||
631 | */ | ||
632 | static inline size_t read_zero_pagealigned(char __user * buf, size_t size) | ||
633 | { | ||
634 | struct mm_struct *mm; | ||
635 | struct vm_area_struct * vma; | ||
636 | unsigned long addr=(unsigned long)buf; | ||
637 | |||
638 | mm = current->mm; | ||
639 | /* Oops, this was forgotten before. -ben */ | ||
640 | down_read(&mm->mmap_sem); | ||
641 | |||
642 | /* For private mappings, just map in zero pages. */ | ||
643 | for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { | ||
644 | unsigned long count; | ||
645 | |||
646 | if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) | ||
647 | goto out_up; | ||
648 | if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) | ||
649 | break; | ||
650 | count = vma->vm_end - addr; | ||
651 | if (count > size) | ||
652 | count = size; | ||
653 | |||
654 | zap_page_range(vma, addr, count, NULL); | ||
655 | if (zeromap_page_range(vma, addr, count, PAGE_COPY)) | ||
656 | break; | ||
657 | |||
658 | size -= count; | ||
659 | buf += count; | ||
660 | addr += count; | ||
661 | if (size == 0) | ||
662 | goto out_up; | ||
663 | } | ||
664 | |||
665 | up_read(&mm->mmap_sem); | ||
666 | |||
667 | /* The shared case is hard. Let's do the conventional zeroing. */ | ||
668 | do { | ||
669 | unsigned long unwritten = clear_user(buf, PAGE_SIZE); | ||
670 | if (unwritten) | ||
671 | return size + unwritten - PAGE_SIZE; | ||
672 | cond_resched(); | ||
673 | buf += PAGE_SIZE; | ||
674 | size -= PAGE_SIZE; | ||
675 | } while (size); | ||
676 | |||
677 | return size; | ||
678 | out_up: | ||
679 | up_read(&mm->mmap_sem); | ||
680 | return size; | ||
681 | } | ||
682 | |||
683 | static ssize_t read_zero(struct file * file, char __user * buf, | 628 | static ssize_t read_zero(struct file * file, char __user * buf, |
684 | size_t count, loff_t *ppos) | 629 | size_t count, loff_t *ppos) |
685 | { | 630 | { |
686 | unsigned long left, unwritten, written = 0; | 631 | size_t written; |
687 | 632 | ||
688 | if (!count) | 633 | if (!count) |
689 | return 0; | 634 | return 0; |
@@ -691,69 +636,33 @@ static ssize_t read_zero(struct file * file, char __user * buf, | |||
691 | if (!access_ok(VERIFY_WRITE, buf, count)) | 636 | if (!access_ok(VERIFY_WRITE, buf, count)) |
692 | return -EFAULT; | 637 | return -EFAULT; |
693 | 638 | ||
694 | left = count; | 639 | written = 0; |
695 | 640 | while (count) { | |
696 | /* do we want to be clever? Arbitrary cut-off */ | 641 | unsigned long unwritten; |
697 | if (count >= PAGE_SIZE*4) { | 642 | size_t chunk = count; |
698 | unsigned long partial; | ||
699 | 643 | ||
700 | /* How much left of the page? */ | 644 | if (chunk > PAGE_SIZE) |
701 | partial = (PAGE_SIZE-1) & -(unsigned long) buf; | 645 | chunk = PAGE_SIZE; /* Just for latency reasons */ |
702 | unwritten = clear_user(buf, partial); | 646 | unwritten = clear_user(buf, chunk); |
703 | written = partial - unwritten; | 647 | written += chunk - unwritten; |
704 | if (unwritten) | ||
705 | goto out; | ||
706 | left -= partial; | ||
707 | buf += partial; | ||
708 | unwritten = read_zero_pagealigned(buf, left & PAGE_MASK); | ||
709 | written += (left & PAGE_MASK) - unwritten; | ||
710 | if (unwritten) | 648 | if (unwritten) |
711 | goto out; | 649 | break; |
712 | buf += left & PAGE_MASK; | ||
713 | left &= ~PAGE_MASK; | ||
714 | } | ||
715 | unwritten = clear_user(buf, left); | ||
716 | written += left - unwritten; | ||
717 | out: | ||
718 | return written ? written : -EFAULT; | ||
719 | } | ||
720 | |||
721 | static int mmap_zero(struct file * file, struct vm_area_struct * vma) | ||
722 | { | ||
723 | int err; | ||
724 | |||
725 | if (vma->vm_flags & VM_SHARED) | ||
726 | return shmem_zero_setup(vma); | ||
727 | err = zeromap_page_range(vma, vma->vm_start, | ||
728 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
729 | BUG_ON(err == -EEXIST); | ||
730 | return err; | ||
731 | } | ||
732 | #else /* CONFIG_MMU */ | ||
733 | static ssize_t read_zero(struct file * file, char * buf, | ||
734 | size_t count, loff_t *ppos) | ||
735 | { | ||
736 | size_t todo = count; | ||
737 | |||
738 | while (todo) { | ||
739 | size_t chunk = todo; | ||
740 | |||
741 | if (chunk > 4096) | ||
742 | chunk = 4096; /* Just for latency reasons */ | ||
743 | if (clear_user(buf, chunk)) | ||
744 | return -EFAULT; | ||
745 | buf += chunk; | 650 | buf += chunk; |
746 | todo -= chunk; | 651 | count -= chunk; |
747 | cond_resched(); | 652 | cond_resched(); |
748 | } | 653 | } |
749 | return count; | 654 | return written ? written : -EFAULT; |
750 | } | 655 | } |
751 | 656 | ||
752 | static int mmap_zero(struct file * file, struct vm_area_struct * vma) | 657 | static int mmap_zero(struct file * file, struct vm_area_struct * vma) |
753 | { | 658 | { |
659 | #ifndef CONFIG_MMU | ||
754 | return -ENOSYS; | 660 | return -ENOSYS; |
661 | #endif | ||
662 | if (vma->vm_flags & VM_SHARED) | ||
663 | return shmem_zero_setup(vma); | ||
664 | return 0; | ||
755 | } | 665 | } |
756 | #endif /* CONFIG_MMU */ | ||
757 | 666 | ||
758 | static ssize_t write_full(struct file * file, const char __user * buf, | 667 | static ssize_t write_full(struct file * file, const char __user * buf, |
759 | size_t count, loff_t *ppos) | 668 | size_t count, loff_t *ppos) |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 04ac155d3a07..82f2e27dca7d 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -362,7 +362,7 @@ mspec_init(void) | |||
362 | is_sn2 = 1; | 362 | is_sn2 = 1; |
363 | if (is_shub2()) { | 363 | if (is_shub2()) { |
364 | ret = -ENOMEM; | 364 | ret = -ENOMEM; |
365 | for_each_online_node(nid) { | 365 | for_each_node_state(nid, N_ONLINE) { |
366 | int actual_nid; | 366 | int actual_nid; |
367 | int nasid; | 367 | int nasid; |
368 | unsigned long phys; | 368 | unsigned long phys; |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index edb7002a3216..0d56f8fc105c 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -750,13 +750,15 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
750 | return 0; | 750 | return 0; |
751 | } | 751 | } |
752 | 752 | ||
753 | static inline int resize_screen(struct vc_data *vc, int width, int height) | 753 | static inline int resize_screen(struct vc_data *vc, int width, int height, |
754 | int user) | ||
754 | { | 755 | { |
755 | /* Resizes the resolution of the display adapater */ | 756 | /* Resizes the resolution of the display adapater */ |
756 | int err = 0; | 757 | int err = 0; |
757 | 758 | ||
758 | if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) | 759 | if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) |
759 | err = vc->vc_sw->con_resize(vc, width, height); | 760 | err = vc->vc_sw->con_resize(vc, width, height, user); |
761 | |||
760 | return err; | 762 | return err; |
761 | } | 763 | } |
762 | 764 | ||
@@ -772,7 +774,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
772 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; | 774 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; |
773 | unsigned int old_cols, old_rows, old_row_size, old_screen_size; | 775 | unsigned int old_cols, old_rows, old_row_size, old_screen_size; |
774 | unsigned int new_cols, new_rows, new_row_size, new_screen_size; | 776 | unsigned int new_cols, new_rows, new_row_size, new_screen_size; |
775 | unsigned int end; | 777 | unsigned int end, user; |
776 | unsigned short *newscreen; | 778 | unsigned short *newscreen; |
777 | 779 | ||
778 | WARN_CONSOLE_UNLOCKED(); | 780 | WARN_CONSOLE_UNLOCKED(); |
@@ -780,6 +782,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
780 | if (!vc) | 782 | if (!vc) |
781 | return -ENXIO; | 783 | return -ENXIO; |
782 | 784 | ||
785 | user = vc->vc_resize_user; | ||
786 | vc->vc_resize_user = 0; | ||
787 | |||
783 | if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) | 788 | if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) |
784 | return -EINVAL; | 789 | return -EINVAL; |
785 | 790 | ||
@@ -800,7 +805,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
800 | old_row_size = vc->vc_size_row; | 805 | old_row_size = vc->vc_size_row; |
801 | old_screen_size = vc->vc_screenbuf_size; | 806 | old_screen_size = vc->vc_screenbuf_size; |
802 | 807 | ||
803 | err = resize_screen(vc, new_cols, new_rows); | 808 | err = resize_screen(vc, new_cols, new_rows, user); |
804 | if (err) { | 809 | if (err) { |
805 | kfree(newscreen); | 810 | kfree(newscreen); |
806 | return err; | 811 | return err; |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 7a61a2a9aafe..f69a8258095c 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
@@ -847,14 +847,24 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
847 | case VT_RESIZE: | 847 | case VT_RESIZE: |
848 | { | 848 | { |
849 | struct vt_sizes __user *vtsizes = up; | 849 | struct vt_sizes __user *vtsizes = up; |
850 | struct vc_data *vc; | ||
851 | |||
850 | ushort ll,cc; | 852 | ushort ll,cc; |
851 | if (!perm) | 853 | if (!perm) |
852 | return -EPERM; | 854 | return -EPERM; |
853 | if (get_user(ll, &vtsizes->v_rows) || | 855 | if (get_user(ll, &vtsizes->v_rows) || |
854 | get_user(cc, &vtsizes->v_cols)) | 856 | get_user(cc, &vtsizes->v_cols)) |
855 | return -EFAULT; | 857 | return -EFAULT; |
856 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 858 | |
857 | vc_lock_resize(vc_cons[i].d, cc, ll); | 859 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
860 | vc = vc_cons[i].d; | ||
861 | |||
862 | if (vc) { | ||
863 | vc->vc_resize_user = 1; | ||
864 | vc_lock_resize(vc_cons[i].d, cc, ll); | ||
865 | } | ||
866 | } | ||
867 | |||
858 | return 0; | 868 | return 0; |
859 | } | 869 | } |
860 | 870 | ||
@@ -900,6 +910,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
900 | vc_cons[i].d->vc_scan_lines = vlin; | 910 | vc_cons[i].d->vc_scan_lines = vlin; |
901 | if (clin) | 911 | if (clin) |
902 | vc_cons[i].d->vc_font.height = clin; | 912 | vc_cons[i].d->vc_font.height = clin; |
913 | vc_cons[i].d->vc_resize_user = 1; | ||
903 | vc_resize(vc_cons[i].d, cc, ll); | 914 | vc_resize(vc_cons[i].d, cc, ll); |
904 | release_console_sem(); | 915 | release_console_sem(); |
905 | } | 916 | } |
diff --git a/drivers/dca/Kconfig b/drivers/dca/Kconfig new file mode 100644 index 000000000000..94f0364a0efb --- /dev/null +++ b/drivers/dca/Kconfig | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # DCA server configuration | ||
3 | # | ||
4 | |||
5 | config DCA | ||
6 | tristate | ||
7 | |||
diff --git a/drivers/dca/Makefile b/drivers/dca/Makefile new file mode 100644 index 000000000000..b2db56bb9dde --- /dev/null +++ b/drivers/dca/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_DCA) += dca.o | ||
2 | dca-objs := dca-core.o dca-sysfs.o | ||
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c new file mode 100644 index 000000000000..bf5b92f86df7 --- /dev/null +++ b/drivers/dca/dca-core.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Copyright(c) 2007 Intel Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the Free | ||
6 | * Software Foundation; either version 2 of the License, or (at your option) | ||
7 | * any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
16 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called COPYING. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * This driver supports an interface for DCA clients and providers to meet. | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/notifier.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/dca.h> | ||
30 | |||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* For now we're assuming a single, global, DCA provider for the system. */ | ||
34 | |||
35 | static DEFINE_SPINLOCK(dca_lock); | ||
36 | |||
37 | static struct dca_provider *global_dca = NULL; | ||
38 | |||
39 | /** | ||
40 | * dca_add_requester - add a dca client to the list | ||
41 | * @dev - the device that wants dca service | ||
42 | */ | ||
43 | int dca_add_requester(struct device *dev) | ||
44 | { | ||
45 | int err, slot; | ||
46 | |||
47 | if (!global_dca) | ||
48 | return -ENODEV; | ||
49 | |||
50 | spin_lock(&dca_lock); | ||
51 | slot = global_dca->ops->add_requester(global_dca, dev); | ||
52 | spin_unlock(&dca_lock); | ||
53 | if (slot < 0) | ||
54 | return slot; | ||
55 | |||
56 | err = dca_sysfs_add_req(global_dca, dev, slot); | ||
57 | if (err) { | ||
58 | spin_lock(&dca_lock); | ||
59 | global_dca->ops->remove_requester(global_dca, dev); | ||
60 | spin_unlock(&dca_lock); | ||
61 | return err; | ||
62 | } | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(dca_add_requester); | ||
67 | |||
68 | /** | ||
69 | * dca_remove_requester - remove a dca client from the list | ||
70 | * @dev - the device that wants dca service | ||
71 | */ | ||
72 | int dca_remove_requester(struct device *dev) | ||
73 | { | ||
74 | int slot; | ||
75 | if (!global_dca) | ||
76 | return -ENODEV; | ||
77 | |||
78 | spin_lock(&dca_lock); | ||
79 | slot = global_dca->ops->remove_requester(global_dca, dev); | ||
80 | spin_unlock(&dca_lock); | ||
81 | if (slot < 0) | ||
82 | return slot; | ||
83 | |||
84 | dca_sysfs_remove_req(global_dca, slot); | ||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(dca_remove_requester); | ||
88 | |||
89 | /** | ||
90 | * dca_get_tag - return the dca tag for the given cpu | ||
91 | * @cpu - the cpuid as returned by get_cpu() | ||
92 | */ | ||
93 | u8 dca_get_tag(int cpu) | ||
94 | { | ||
95 | if (!global_dca) | ||
96 | return -ENODEV; | ||
97 | return global_dca->ops->get_tag(global_dca, cpu); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(dca_get_tag); | ||
100 | |||
101 | /** | ||
102 | * alloc_dca_provider - get data struct for describing a dca provider | ||
103 | * @ops - pointer to struct of dca operation function pointers | ||
104 | * @priv_size - size of extra mem to be added for provider's needs | ||
105 | */ | ||
106 | struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size) | ||
107 | { | ||
108 | struct dca_provider *dca; | ||
109 | int alloc_size; | ||
110 | |||
111 | alloc_size = (sizeof(*dca) + priv_size); | ||
112 | dca = kzalloc(alloc_size, GFP_KERNEL); | ||
113 | if (!dca) | ||
114 | return NULL; | ||
115 | dca->ops = ops; | ||
116 | |||
117 | return dca; | ||
118 | } | ||
119 | EXPORT_SYMBOL_GPL(alloc_dca_provider); | ||
120 | |||
121 | /** | ||
122 | * free_dca_provider - release the dca provider data struct | ||
123 | * @ops - pointer to struct of dca operation function pointers | ||
124 | * @priv_size - size of extra mem to be added for provider's needs | ||
125 | */ | ||
126 | void free_dca_provider(struct dca_provider *dca) | ||
127 | { | ||
128 | kfree(dca); | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(free_dca_provider); | ||
131 | |||
132 | static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); | ||
133 | |||
134 | /** | ||
135 | * register_dca_provider - register a dca provider | ||
136 | * @dca - struct created by alloc_dca_provider() | ||
137 | * @dev - device providing dca services | ||
138 | */ | ||
139 | int register_dca_provider(struct dca_provider *dca, struct device *dev) | ||
140 | { | ||
141 | int err; | ||
142 | |||
143 | if (global_dca) | ||
144 | return -EEXIST; | ||
145 | err = dca_sysfs_add_provider(dca, dev); | ||
146 | if (err) | ||
147 | return err; | ||
148 | global_dca = dca; | ||
149 | blocking_notifier_call_chain(&dca_provider_chain, | ||
150 | DCA_PROVIDER_ADD, NULL); | ||
151 | return 0; | ||
152 | } | ||
153 | EXPORT_SYMBOL_GPL(register_dca_provider); | ||
154 | |||
155 | /** | ||
156 | * unregister_dca_provider - remove a dca provider | ||
157 | * @dca - struct created by alloc_dca_provider() | ||
158 | */ | ||
159 | void unregister_dca_provider(struct dca_provider *dca) | ||
160 | { | ||
161 | if (!global_dca) | ||
162 | return; | ||
163 | blocking_notifier_call_chain(&dca_provider_chain, | ||
164 | DCA_PROVIDER_REMOVE, NULL); | ||
165 | global_dca = NULL; | ||
166 | dca_sysfs_remove_provider(dca); | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(unregister_dca_provider); | ||
169 | |||
170 | /** | ||
171 | * dca_register_notify - register a client's notifier callback | ||
172 | */ | ||
173 | void dca_register_notify(struct notifier_block *nb) | ||
174 | { | ||
175 | blocking_notifier_chain_register(&dca_provider_chain, nb); | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(dca_register_notify); | ||
178 | |||
179 | /** | ||
180 | * dca_unregister_notify - remove a client's notifier callback | ||
181 | */ | ||
182 | void dca_unregister_notify(struct notifier_block *nb) | ||
183 | { | ||
184 | blocking_notifier_chain_unregister(&dca_provider_chain, nb); | ||
185 | } | ||
186 | EXPORT_SYMBOL_GPL(dca_unregister_notify); | ||
187 | |||
188 | static int __init dca_init(void) | ||
189 | { | ||
190 | return dca_sysfs_init(); | ||
191 | } | ||
192 | |||
193 | static void __exit dca_exit(void) | ||
194 | { | ||
195 | dca_sysfs_exit(); | ||
196 | } | ||
197 | |||
198 | module_init(dca_init); | ||
199 | module_exit(dca_exit); | ||
200 | |||
diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c new file mode 100644 index 000000000000..24a263b6844c --- /dev/null +++ b/drivers/dca/dca-sysfs.c | |||
@@ -0,0 +1,88 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/spinlock.h> | ||
3 | #include <linux/device.h> | ||
4 | #include <linux/idr.h> | ||
5 | #include <linux/kdev_t.h> | ||
6 | #include <linux/err.h> | ||
7 | #include <linux/dca.h> | ||
8 | |||
9 | static struct class *dca_class; | ||
10 | static struct idr dca_idr; | ||
11 | static spinlock_t dca_idr_lock; | ||
12 | |||
13 | int dca_sysfs_add_req(struct dca_provider *dca, struct device *dev, int slot) | ||
14 | { | ||
15 | struct class_device *cd; | ||
16 | |||
17 | cd = class_device_create(dca_class, dca->cd, MKDEV(0, slot + 1), | ||
18 | dev, "requester%d", slot); | ||
19 | if (IS_ERR(cd)) | ||
20 | return PTR_ERR(cd); | ||
21 | return 0; | ||
22 | } | ||
23 | |||
24 | void dca_sysfs_remove_req(struct dca_provider *dca, int slot) | ||
25 | { | ||
26 | class_device_destroy(dca_class, MKDEV(0, slot + 1)); | ||
27 | } | ||
28 | |||
29 | int dca_sysfs_add_provider(struct dca_provider *dca, struct device *dev) | ||
30 | { | ||
31 | struct class_device *cd; | ||
32 | int err = 0; | ||
33 | |||
34 | idr_try_again: | ||
35 | if (!idr_pre_get(&dca_idr, GFP_KERNEL)) | ||
36 | return -ENOMEM; | ||
37 | spin_lock(&dca_idr_lock); | ||
38 | err = idr_get_new(&dca_idr, dca, &dca->id); | ||
39 | spin_unlock(&dca_idr_lock); | ||
40 | switch (err) { | ||
41 | case 0: | ||
42 | break; | ||
43 | case -EAGAIN: | ||
44 | goto idr_try_again; | ||
45 | default: | ||
46 | return err; | ||
47 | } | ||
48 | |||
49 | cd = class_device_create(dca_class, NULL, MKDEV(0, 0), | ||
50 | dev, "dca%d", dca->id); | ||
51 | if (IS_ERR(cd)) { | ||
52 | spin_lock(&dca_idr_lock); | ||
53 | idr_remove(&dca_idr, dca->id); | ||
54 | spin_unlock(&dca_idr_lock); | ||
55 | return PTR_ERR(cd); | ||
56 | } | ||
57 | dca->cd = cd; | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | void dca_sysfs_remove_provider(struct dca_provider *dca) | ||
62 | { | ||
63 | class_device_unregister(dca->cd); | ||
64 | dca->cd = NULL; | ||
65 | spin_lock(&dca_idr_lock); | ||
66 | idr_remove(&dca_idr, dca->id); | ||
67 | spin_unlock(&dca_idr_lock); | ||
68 | } | ||
69 | |||
70 | int __init dca_sysfs_init(void) | ||
71 | { | ||
72 | idr_init(&dca_idr); | ||
73 | spin_lock_init(&dca_idr_lock); | ||
74 | |||
75 | dca_class = class_create(THIS_MODULE, "dca"); | ||
76 | if (IS_ERR(dca_class)) { | ||
77 | idr_destroy(&dca_idr); | ||
78 | return PTR_ERR(dca_class); | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void __exit dca_sysfs_exit(void) | ||
84 | { | ||
85 | class_destroy(dca_class); | ||
86 | idr_destroy(&dca_idr); | ||
87 | } | ||
88 | |||
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 8f670dae53bb..9c91b0fd134f 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig | |||
@@ -2,42 +2,52 @@ | |||
2 | # DMA engine configuration | 2 | # DMA engine configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "DMA Engine support" | 5 | menuconfig DMADEVICES |
6 | depends on HAS_DMA | 6 | bool "DMA Offload Engine support" |
7 | depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX | ||
8 | help | ||
9 | Intel(R) offload engines enable offloading memory copies in the | ||
10 | network stack and RAID operations in the MD driver. | ||
11 | |||
12 | if DMADEVICES | ||
13 | |||
14 | comment "DMA Devices" | ||
15 | |||
16 | config INTEL_IOATDMA | ||
17 | tristate "Intel I/OAT DMA support" | ||
18 | depends on PCI && X86 | ||
19 | select DMA_ENGINE | ||
20 | select DCA | ||
21 | help | ||
22 | Enable support for the Intel(R) I/OAT DMA engine present | ||
23 | in recent Intel Xeon chipsets. | ||
24 | |||
25 | Say Y here if you have such a chipset. | ||
26 | |||
27 | If unsure, say N. | ||
28 | |||
29 | config INTEL_IOP_ADMA | ||
30 | tristate "Intel IOP ADMA support" | ||
31 | depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX | ||
32 | select ASYNC_CORE | ||
33 | select DMA_ENGINE | ||
34 | help | ||
35 | Enable support for the Intel(R) IOP Series RAID engines. | ||
7 | 36 | ||
8 | config DMA_ENGINE | 37 | config DMA_ENGINE |
9 | bool "Support for DMA engines" | 38 | bool |
10 | ---help--- | ||
11 | DMA engines offload bulk memory operations from the CPU to dedicated | ||
12 | hardware, allowing the operations to happen asynchronously. | ||
13 | 39 | ||
14 | comment "DMA Clients" | 40 | comment "DMA Clients" |
41 | depends on DMA_ENGINE | ||
15 | 42 | ||
16 | config NET_DMA | 43 | config NET_DMA |
17 | bool "Network: TCP receive copy offload" | 44 | bool "Network: TCP receive copy offload" |
18 | depends on DMA_ENGINE && NET | 45 | depends on DMA_ENGINE && NET |
19 | default y | 46 | default y |
20 | ---help--- | 47 | help |
21 | This enables the use of DMA engines in the network stack to | 48 | This enables the use of DMA engines in the network stack to |
22 | offload receive copy-to-user operations, freeing CPU cycles. | 49 | offload receive copy-to-user operations, freeing CPU cycles. |
23 | Since this is the main user of the DMA engine, it should be enabled; | 50 | Since this is the main user of the DMA engine, it should be enabled; |
24 | say Y here. | 51 | say Y here. |
25 | 52 | ||
26 | comment "DMA Devices" | 53 | endif |
27 | |||
28 | config INTEL_IOATDMA | ||
29 | tristate "Intel I/OAT DMA support" | ||
30 | depends on DMA_ENGINE && PCI | ||
31 | default m | ||
32 | ---help--- | ||
33 | Enable support for the Intel(R) I/OAT DMA engine. | ||
34 | |||
35 | config INTEL_IOP_ADMA | ||
36 | tristate "Intel IOP ADMA support" | ||
37 | depends on DMA_ENGINE && (ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX) | ||
38 | select ASYNC_CORE | ||
39 | default m | ||
40 | ---help--- | ||
41 | Enable support for the Intel(R) IOP Series RAID engines. | ||
42 | |||
43 | endmenu | ||
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index b3839b687ae0..b152cd84e123 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_DMA_ENGINE) += dmaengine.o | 1 | obj-$(CONFIG_DMA_ENGINE) += dmaengine.o |
2 | obj-$(CONFIG_NET_DMA) += iovlock.o | 2 | obj-$(CONFIG_NET_DMA) += iovlock.o |
3 | obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o | 3 | obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o |
4 | ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o | ||
4 | obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o | 5 | obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o |
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c new file mode 100644 index 000000000000..f7276bf2fe7e --- /dev/null +++ b/drivers/dma/ioat.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Intel I/OAT DMA Linux driver | ||
3 | * Copyright(c) 2007 Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * This driver supports an Intel I/OAT DMA engine, which does asynchronous | ||
25 | * copy operations. | ||
26 | */ | ||
27 | |||
28 | #include <linux/init.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/dca.h> | ||
33 | #include "ioatdma.h" | ||
34 | #include "ioatdma_registers.h" | ||
35 | #include "ioatdma_hw.h" | ||
36 | |||
37 | MODULE_VERSION("1.24"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | MODULE_AUTHOR("Intel Corporation"); | ||
40 | |||
41 | static struct pci_device_id ioat_pci_tbl[] = { | ||
42 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) }, | ||
43 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) }, | ||
44 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) }, | ||
45 | { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) }, | ||
46 | { 0, } | ||
47 | }; | ||
48 | |||
49 | struct ioat_device { | ||
50 | struct pci_dev *pdev; | ||
51 | void __iomem *iobase; | ||
52 | struct ioatdma_device *dma; | ||
53 | struct dca_provider *dca; | ||
54 | }; | ||
55 | |||
56 | static int __devinit ioat_probe(struct pci_dev *pdev, | ||
57 | const struct pci_device_id *id); | ||
58 | #ifdef IOAT_DMA_REMOVE | ||
59 | static void __devexit ioat_remove(struct pci_dev *pdev); | ||
60 | #endif | ||
61 | |||
62 | static int ioat_dca_enabled = 1; | ||
63 | module_param(ioat_dca_enabled, int, 0644); | ||
64 | MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); | ||
65 | |||
66 | static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase) | ||
67 | { | ||
68 | struct ioat_device *device = pci_get_drvdata(pdev); | ||
69 | u8 version; | ||
70 | int err = 0; | ||
71 | |||
72 | version = readb(iobase + IOAT_VER_OFFSET); | ||
73 | switch (version) { | ||
74 | case IOAT_VER_1_2: | ||
75 | device->dma = ioat_dma_probe(pdev, iobase); | ||
76 | if (ioat_dca_enabled) | ||
77 | device->dca = ioat_dca_init(pdev, iobase); | ||
78 | break; | ||
79 | default: | ||
80 | err = -ENODEV; | ||
81 | break; | ||
82 | } | ||
83 | return err; | ||
84 | } | ||
85 | |||
86 | static void ioat_shutdown_functionality(struct pci_dev *pdev) | ||
87 | { | ||
88 | struct ioat_device *device = pci_get_drvdata(pdev); | ||
89 | |||
90 | if (device->dma) { | ||
91 | ioat_dma_remove(device->dma); | ||
92 | device->dma = NULL; | ||
93 | } | ||
94 | |||
95 | if (device->dca) { | ||
96 | unregister_dca_provider(device->dca); | ||
97 | free_dca_provider(device->dca); | ||
98 | device->dca = NULL; | ||
99 | } | ||
100 | |||
101 | } | ||
102 | |||
103 | static struct pci_driver ioat_pci_drv = { | ||
104 | .name = "ioatdma", | ||
105 | .id_table = ioat_pci_tbl, | ||
106 | .probe = ioat_probe, | ||
107 | .shutdown = ioat_shutdown_functionality, | ||
108 | #ifdef IOAT_DMA_REMOVE | ||
109 | .remove = __devexit_p(ioat_remove), | ||
110 | #endif | ||
111 | }; | ||
112 | |||
113 | static int __devinit ioat_probe(struct pci_dev *pdev, | ||
114 | const struct pci_device_id *id) | ||
115 | { | ||
116 | void __iomem *iobase; | ||
117 | struct ioat_device *device; | ||
118 | unsigned long mmio_start, mmio_len; | ||
119 | int err; | ||
120 | |||
121 | err = pci_enable_device(pdev); | ||
122 | if (err) | ||
123 | goto err_enable_device; | ||
124 | |||
125 | err = pci_request_regions(pdev, ioat_pci_drv.name); | ||
126 | if (err) | ||
127 | goto err_request_regions; | ||
128 | |||
129 | err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | ||
130 | if (err) | ||
131 | err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
132 | if (err) | ||
133 | goto err_set_dma_mask; | ||
134 | |||
135 | err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); | ||
136 | if (err) | ||
137 | err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | ||
138 | if (err) | ||
139 | goto err_set_dma_mask; | ||
140 | |||
141 | mmio_start = pci_resource_start(pdev, 0); | ||
142 | mmio_len = pci_resource_len(pdev, 0); | ||
143 | iobase = ioremap(mmio_start, mmio_len); | ||
144 | if (!iobase) { | ||
145 | err = -ENOMEM; | ||
146 | goto err_ioremap; | ||
147 | } | ||
148 | |||
149 | device = kzalloc(sizeof(*device), GFP_KERNEL); | ||
150 | if (!device) { | ||
151 | err = -ENOMEM; | ||
152 | goto err_kzalloc; | ||
153 | } | ||
154 | device->pdev = pdev; | ||
155 | pci_set_drvdata(pdev, device); | ||
156 | device->iobase = iobase; | ||
157 | |||
158 | pci_set_master(pdev); | ||
159 | |||
160 | err = ioat_setup_functionality(pdev, iobase); | ||
161 | if (err) | ||
162 | goto err_version; | ||
163 | |||
164 | return 0; | ||
165 | |||
166 | err_version: | ||
167 | kfree(device); | ||
168 | err_kzalloc: | ||
169 | iounmap(iobase); | ||
170 | err_ioremap: | ||
171 | err_set_dma_mask: | ||
172 | pci_release_regions(pdev); | ||
173 | pci_disable_device(pdev); | ||
174 | err_request_regions: | ||
175 | err_enable_device: | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | #ifdef IOAT_DMA_REMOVE | ||
180 | /* | ||
181 | * It is unsafe to remove this module: if removed while a requested | ||
182 | * dma is outstanding, esp. from tcp, it is possible to hang while | ||
183 | * waiting for something that will never finish, thus hanging at | ||
184 | * least one cpu. However, if you're feeling lucky and need to do | ||
185 | * some testing, this usually works just fine. | ||
186 | */ | ||
187 | static void __devexit ioat_remove(struct pci_dev *pdev) | ||
188 | { | ||
189 | struct ioat_device *device = pci_get_drvdata(pdev); | ||
190 | |||
191 | ioat_shutdown_functionality(pdev); | ||
192 | |||
193 | kfree(device); | ||
194 | |||
195 | iounmap(device->iobase); | ||
196 | pci_release_regions(pdev); | ||
197 | pci_disable_device(pdev); | ||
198 | } | ||
199 | #endif | ||
200 | |||
201 | static int __init ioat_init_module(void) | ||
202 | { | ||
203 | return pci_register_driver(&ioat_pci_drv); | ||
204 | } | ||
205 | module_init(ioat_init_module); | ||
206 | |||
207 | static void __exit ioat_exit_module(void) | ||
208 | { | ||
209 | pci_unregister_driver(&ioat_pci_drv); | ||
210 | } | ||
211 | module_exit(ioat_exit_module); | ||
diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat_dca.c new file mode 100644 index 000000000000..2ae04c30edeb --- /dev/null +++ b/drivers/dma/ioat_dca.c | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * Intel I/OAT DMA Linux driver | ||
3 | * Copyright(c) 2007 Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/smp.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/dca.h> | ||
28 | |||
29 | /* either a kernel change is needed, or we need something like this in kernel */ | ||
30 | #ifndef CONFIG_SMP | ||
31 | #include <asm/smp.h> | ||
32 | #undef cpu_physical_id | ||
33 | #define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24) | ||
34 | #endif | ||
35 | |||
36 | #include "ioatdma.h" | ||
37 | #include "ioatdma_registers.h" | ||
38 | |||
39 | /* | ||
40 | * Bit 16 of a tag map entry is the "valid" bit, if it is set then bits 0:15 | ||
41 | * contain the bit number of the APIC ID to map into the DCA tag. If the valid | ||
42 | * bit is not set, then the value must be 0 or 1 and defines the bit in the tag. | ||
43 | */ | ||
44 | #define DCA_TAG_MAP_VALID 0x80 | ||
45 | |||
46 | /* | ||
47 | * "Legacy" DCA systems do not implement the DCA register set in the | ||
48 | * I/OAT device. Software needs direct support for their tag mappings. | ||
49 | */ | ||
50 | |||
51 | #define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x)) | ||
52 | #define IOAT_TAG_MAP_LEN 8 | ||
53 | |||
54 | static u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = { | ||
55 | 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; | ||
56 | static u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = { | ||
57 | 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; | ||
58 | static u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = { | ||
59 | 1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), }; | ||
60 | static u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 }; | ||
61 | |||
62 | /* pack PCI B/D/F into a u16 */ | ||
63 | static inline u16 dcaid_from_pcidev(struct pci_dev *pci) | ||
64 | { | ||
65 | return (pci->bus->number << 8) | pci->devfn; | ||
66 | } | ||
67 | |||
68 | static int dca_enabled_in_bios(void) | ||
69 | { | ||
70 | /* CPUID level 9 returns DCA configuration */ | ||
71 | /* Bit 0 indicates DCA enabled by the BIOS */ | ||
72 | unsigned long cpuid_level_9; | ||
73 | int res; | ||
74 | |||
75 | cpuid_level_9 = cpuid_eax(9); | ||
76 | res = test_bit(0, &cpuid_level_9); | ||
77 | if (!res) | ||
78 | printk(KERN_ERR "ioat dma: DCA is disabled in BIOS\n"); | ||
79 | |||
80 | return res; | ||
81 | } | ||
82 | |||
83 | static int system_has_dca_enabled(void) | ||
84 | { | ||
85 | if (boot_cpu_has(X86_FEATURE_DCA)) | ||
86 | return dca_enabled_in_bios(); | ||
87 | |||
88 | printk(KERN_ERR "ioat dma: boot cpu doesn't have X86_FEATURE_DCA\n"); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | struct ioat_dca_slot { | ||
93 | struct pci_dev *pdev; /* requester device */ | ||
94 | u16 rid; /* requester id, as used by IOAT */ | ||
95 | }; | ||
96 | |||
97 | #define IOAT_DCA_MAX_REQ 6 | ||
98 | |||
99 | struct ioat_dca_priv { | ||
100 | void __iomem *iobase; | ||
101 | void *dca_base; | ||
102 | int max_requesters; | ||
103 | int requester_count; | ||
104 | u8 tag_map[IOAT_TAG_MAP_LEN]; | ||
105 | struct ioat_dca_slot req_slots[0]; | ||
106 | }; | ||
107 | |||
108 | /* 5000 series chipset DCA Port Requester ID Table Entry Format | ||
109 | * [15:8] PCI-Express Bus Number | ||
110 | * [7:3] PCI-Express Device Number | ||
111 | * [2:0] PCI-Express Function Number | ||
112 | * | ||
113 | * 5000 series chipset DCA control register format | ||
114 | * [7:1] Reserved (0) | ||
115 | * [0] Ignore Function Number | ||
116 | */ | ||
117 | |||
118 | static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) | ||
119 | { | ||
120 | struct ioat_dca_priv *ioatdca = dca_priv(dca); | ||
121 | struct pci_dev *pdev; | ||
122 | int i; | ||
123 | u16 id; | ||
124 | |||
125 | /* This implementation only supports PCI-Express */ | ||
126 | if (dev->bus != &pci_bus_type) | ||
127 | return -ENODEV; | ||
128 | pdev = to_pci_dev(dev); | ||
129 | id = dcaid_from_pcidev(pdev); | ||
130 | |||
131 | if (ioatdca->requester_count == ioatdca->max_requesters) | ||
132 | return -ENODEV; | ||
133 | |||
134 | for (i = 0; i < ioatdca->max_requesters; i++) { | ||
135 | if (ioatdca->req_slots[i].pdev == NULL) { | ||
136 | /* found an empty slot */ | ||
137 | ioatdca->requester_count++; | ||
138 | ioatdca->req_slots[i].pdev = pdev; | ||
139 | ioatdca->req_slots[i].rid = id; | ||
140 | writew(id, ioatdca->dca_base + (i * 4)); | ||
141 | /* make sure the ignore function bit is off */ | ||
142 | writeb(0, ioatdca->dca_base + (i * 4) + 2); | ||
143 | return i; | ||
144 | } | ||
145 | } | ||
146 | /* Error, ioatdma->requester_count is out of whack */ | ||
147 | return -EFAULT; | ||
148 | } | ||
149 | |||
150 | static int ioat_dca_remove_requester(struct dca_provider *dca, | ||
151 | struct device *dev) | ||
152 | { | ||
153 | struct ioat_dca_priv *ioatdca = dca_priv(dca); | ||
154 | struct pci_dev *pdev; | ||
155 | int i; | ||
156 | |||
157 | /* This implementation only supports PCI-Express */ | ||
158 | if (dev->bus != &pci_bus_type) | ||
159 | return -ENODEV; | ||
160 | pdev = to_pci_dev(dev); | ||
161 | |||
162 | for (i = 0; i < ioatdca->max_requesters; i++) { | ||
163 | if (ioatdca->req_slots[i].pdev == pdev) { | ||
164 | writew(0, ioatdca->dca_base + (i * 4)); | ||
165 | ioatdca->req_slots[i].pdev = NULL; | ||
166 | ioatdca->req_slots[i].rid = 0; | ||
167 | ioatdca->requester_count--; | ||
168 | return i; | ||
169 | } | ||
170 | } | ||
171 | return -ENODEV; | ||
172 | } | ||
173 | |||
174 | static u8 ioat_dca_get_tag(struct dca_provider *dca, int cpu) | ||
175 | { | ||
176 | struct ioat_dca_priv *ioatdca = dca_priv(dca); | ||
177 | int i, apic_id, bit, value; | ||
178 | u8 entry, tag; | ||
179 | |||
180 | tag = 0; | ||
181 | apic_id = cpu_physical_id(cpu); | ||
182 | |||
183 | for (i = 0; i < IOAT_TAG_MAP_LEN; i++) { | ||
184 | entry = ioatdca->tag_map[i]; | ||
185 | if (entry & DCA_TAG_MAP_VALID) { | ||
186 | bit = entry & ~DCA_TAG_MAP_VALID; | ||
187 | value = (apic_id & (1 << bit)) ? 1 : 0; | ||
188 | } else { | ||
189 | value = entry ? 1 : 0; | ||
190 | } | ||
191 | tag |= (value << i); | ||
192 | } | ||
193 | return tag; | ||
194 | } | ||
195 | |||
196 | static struct dca_ops ioat_dca_ops = { | ||
197 | .add_requester = ioat_dca_add_requester, | ||
198 | .remove_requester = ioat_dca_remove_requester, | ||
199 | .get_tag = ioat_dca_get_tag, | ||
200 | }; | ||
201 | |||
202 | |||
203 | struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) | ||
204 | { | ||
205 | struct dca_provider *dca; | ||
206 | struct ioat_dca_priv *ioatdca; | ||
207 | u8 *tag_map = NULL; | ||
208 | int i; | ||
209 | int err; | ||
210 | |||
211 | if (!system_has_dca_enabled()) | ||
212 | return NULL; | ||
213 | |||
214 | /* I/OAT v1 systems must have a known tag_map to support DCA */ | ||
215 | switch (pdev->vendor) { | ||
216 | case PCI_VENDOR_ID_INTEL: | ||
217 | switch (pdev->device) { | ||
218 | case PCI_DEVICE_ID_INTEL_IOAT: | ||
219 | tag_map = ioat_tag_map_BNB; | ||
220 | break; | ||
221 | case PCI_DEVICE_ID_INTEL_IOAT_CNB: | ||
222 | tag_map = ioat_tag_map_CNB; | ||
223 | break; | ||
224 | case PCI_DEVICE_ID_INTEL_IOAT_SCNB: | ||
225 | tag_map = ioat_tag_map_SCNB; | ||
226 | break; | ||
227 | } | ||
228 | break; | ||
229 | case PCI_VENDOR_ID_UNISYS: | ||
230 | switch (pdev->device) { | ||
231 | case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR: | ||
232 | tag_map = ioat_tag_map_UNISYS; | ||
233 | break; | ||
234 | } | ||
235 | break; | ||
236 | } | ||
237 | if (tag_map == NULL) | ||
238 | return NULL; | ||
239 | |||
240 | dca = alloc_dca_provider(&ioat_dca_ops, | ||
241 | sizeof(*ioatdca) + | ||
242 | (sizeof(struct ioat_dca_slot) * IOAT_DCA_MAX_REQ)); | ||
243 | if (!dca) | ||
244 | return NULL; | ||
245 | |||
246 | ioatdca = dca_priv(dca); | ||
247 | ioatdca->max_requesters = IOAT_DCA_MAX_REQ; | ||
248 | |||
249 | ioatdca->dca_base = iobase + 0x54; | ||
250 | |||
251 | /* copy over the APIC ID to DCA tag mapping */ | ||
252 | for (i = 0; i < IOAT_TAG_MAP_LEN; i++) | ||
253 | ioatdca->tag_map[i] = tag_map[i]; | ||
254 | |||
255 | err = register_dca_provider(dca, &pdev->dev); | ||
256 | if (err) { | ||
257 | free_dca_provider(dca); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | return dca; | ||
262 | } | ||
263 | |||
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioat_dma.c index 41b18c5a3141..66c5bb53211b 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioat_dma.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. | 2 | * Intel I/OAT DMA Linux driver |
3 | * Copyright(c) 2004 - 2007 Intel Corporation. | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 6 | * under the terms and conditions of the GNU General Public License, |
6 | * Software Foundation; either version 2 of the License, or (at your option) | 7 | * version 2, as published by the Free Software Foundation. |
7 | * any later version. | ||
8 | * | 8 | * |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | 9 | * This program is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
@@ -12,11 +12,12 @@ | |||
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License along with | 14 | * You should have received a copy of the GNU General Public License along with |
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 | 15 | * this program; if not, write to the Free Software Foundation, Inc., |
16 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
17 | * | 20 | * |
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called COPYING. | ||
20 | */ | 21 | */ |
21 | 22 | ||
22 | /* | 23 | /* |
@@ -35,17 +36,77 @@ | |||
35 | #include "ioatdma_registers.h" | 36 | #include "ioatdma_registers.h" |
36 | #include "ioatdma_hw.h" | 37 | #include "ioatdma_hw.h" |
37 | 38 | ||
39 | #define INITIAL_IOAT_DESC_COUNT 128 | ||
40 | |||
38 | #define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common) | 41 | #define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common) |
39 | #define to_ioat_device(dev) container_of(dev, struct ioat_device, common) | 42 | #define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, common) |
40 | #define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node) | 43 | #define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node) |
41 | #define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx) | 44 | #define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx) |
42 | 45 | ||
43 | /* internal functions */ | 46 | /* internal functions */ |
44 | static int __devinit ioat_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | 47 | static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan); |
45 | static void ioat_shutdown(struct pci_dev *pdev); | 48 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); |
46 | static void __devexit ioat_remove(struct pci_dev *pdev); | ||
47 | 49 | ||
48 | static int enumerate_dma_channels(struct ioat_device *device) | 50 | static struct ioat_dma_chan *ioat_lookup_chan_by_index(struct ioatdma_device *device, |
51 | int index) | ||
52 | { | ||
53 | return device->idx[index]; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * ioat_dma_do_interrupt - handler used for single vector interrupt mode | ||
58 | * @irq: interrupt id | ||
59 | * @data: interrupt data | ||
60 | */ | ||
61 | static irqreturn_t ioat_dma_do_interrupt(int irq, void *data) | ||
62 | { | ||
63 | struct ioatdma_device *instance = data; | ||
64 | struct ioat_dma_chan *ioat_chan; | ||
65 | unsigned long attnstatus; | ||
66 | int bit; | ||
67 | u8 intrctrl; | ||
68 | |||
69 | intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
70 | |||
71 | if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN)) | ||
72 | return IRQ_NONE; | ||
73 | |||
74 | if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) { | ||
75 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
76 | return IRQ_NONE; | ||
77 | } | ||
78 | |||
79 | attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); | ||
80 | for_each_bit(bit, &attnstatus, BITS_PER_LONG) { | ||
81 | ioat_chan = ioat_lookup_chan_by_index(instance, bit); | ||
82 | tasklet_schedule(&ioat_chan->cleanup_task); | ||
83 | } | ||
84 | |||
85 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
86 | return IRQ_HANDLED; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * ioat_dma_do_interrupt_msix - handler used for vector-per-channel interrupt mode | ||
91 | * @irq: interrupt id | ||
92 | * @data: interrupt data | ||
93 | */ | ||
94 | static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data) | ||
95 | { | ||
96 | struct ioat_dma_chan *ioat_chan = data; | ||
97 | |||
98 | tasklet_schedule(&ioat_chan->cleanup_task); | ||
99 | |||
100 | return IRQ_HANDLED; | ||
101 | } | ||
102 | |||
103 | static void ioat_dma_cleanup_tasklet(unsigned long data); | ||
104 | |||
105 | /** | ||
106 | * ioat_dma_enumerate_channels - find and initialize the device's channels | ||
107 | * @device: the device to be enumerated | ||
108 | */ | ||
109 | static int ioat_dma_enumerate_channels(struct ioatdma_device *device) | ||
49 | { | 110 | { |
50 | u8 xfercap_scale; | 111 | u8 xfercap_scale; |
51 | u32 xfercap; | 112 | u32 xfercap; |
@@ -73,13 +134,19 @@ static int enumerate_dma_channels(struct ioat_device *device) | |||
73 | /* This should be made common somewhere in dmaengine.c */ | 134 | /* This should be made common somewhere in dmaengine.c */ |
74 | ioat_chan->common.device = &device->common; | 135 | ioat_chan->common.device = &device->common; |
75 | list_add_tail(&ioat_chan->common.device_node, | 136 | list_add_tail(&ioat_chan->common.device_node, |
76 | &device->common.channels); | 137 | &device->common.channels); |
138 | device->idx[i] = ioat_chan; | ||
139 | tasklet_init(&ioat_chan->cleanup_task, | ||
140 | ioat_dma_cleanup_tasklet, | ||
141 | (unsigned long) ioat_chan); | ||
142 | tasklet_disable(&ioat_chan->cleanup_task); | ||
77 | } | 143 | } |
78 | return device->common.chancnt; | 144 | return device->common.chancnt; |
79 | } | 145 | } |
80 | 146 | ||
81 | static void | 147 | static void ioat_set_src(dma_addr_t addr, |
82 | ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) | 148 | struct dma_async_tx_descriptor *tx, |
149 | int index) | ||
83 | { | 150 | { |
84 | struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); | 151 | struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); |
85 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); | 152 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); |
@@ -93,8 +160,9 @@ ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) | |||
93 | 160 | ||
94 | } | 161 | } |
95 | 162 | ||
96 | static void | 163 | static void ioat_set_dest(dma_addr_t addr, |
97 | ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) | 164 | struct dma_async_tx_descriptor *tx, |
165 | int index) | ||
98 | { | 166 | { |
99 | struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); | 167 | struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); |
100 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); | 168 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); |
@@ -107,8 +175,7 @@ ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) | |||
107 | } | 175 | } |
108 | } | 176 | } |
109 | 177 | ||
110 | static dma_cookie_t | 178 | static dma_cookie_t ioat_tx_submit(struct dma_async_tx_descriptor *tx) |
111 | ioat_tx_submit(struct dma_async_tx_descriptor *tx) | ||
112 | { | 179 | { |
113 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); | 180 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); |
114 | struct ioat_desc_sw *desc = tx_to_ioat_desc(tx); | 181 | struct ioat_desc_sw *desc = tx_to_ioat_desc(tx); |
@@ -141,27 +208,27 @@ ioat_tx_submit(struct dma_async_tx_descriptor *tx) | |||
141 | if (append) | 208 | if (append) |
142 | writeb(IOAT_CHANCMD_APPEND, | 209 | writeb(IOAT_CHANCMD_APPEND, |
143 | ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); | 210 | ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); |
144 | 211 | ||
145 | return cookie; | 212 | return cookie; |
146 | } | 213 | } |
147 | 214 | ||
148 | static struct ioat_desc_sw *ioat_dma_alloc_descriptor( | 215 | static struct ioat_desc_sw *ioat_dma_alloc_descriptor( |
149 | struct ioat_dma_chan *ioat_chan, | 216 | struct ioat_dma_chan *ioat_chan, |
150 | gfp_t flags) | 217 | gfp_t flags) |
151 | { | 218 | { |
152 | struct ioat_dma_descriptor *desc; | 219 | struct ioat_dma_descriptor *desc; |
153 | struct ioat_desc_sw *desc_sw; | 220 | struct ioat_desc_sw *desc_sw; |
154 | struct ioat_device *ioat_device; | 221 | struct ioatdma_device *ioatdma_device; |
155 | dma_addr_t phys; | 222 | dma_addr_t phys; |
156 | 223 | ||
157 | ioat_device = to_ioat_device(ioat_chan->common.device); | 224 | ioatdma_device = to_ioatdma_device(ioat_chan->common.device); |
158 | desc = pci_pool_alloc(ioat_device->dma_pool, flags, &phys); | 225 | desc = pci_pool_alloc(ioatdma_device->dma_pool, flags, &phys); |
159 | if (unlikely(!desc)) | 226 | if (unlikely(!desc)) |
160 | return NULL; | 227 | return NULL; |
161 | 228 | ||
162 | desc_sw = kzalloc(sizeof(*desc_sw), flags); | 229 | desc_sw = kzalloc(sizeof(*desc_sw), flags); |
163 | if (unlikely(!desc_sw)) { | 230 | if (unlikely(!desc_sw)) { |
164 | pci_pool_free(ioat_device->dma_pool, desc, phys); | 231 | pci_pool_free(ioatdma_device->dma_pool, desc, phys); |
165 | return NULL; | 232 | return NULL; |
166 | } | 233 | } |
167 | 234 | ||
@@ -177,10 +244,6 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor( | |||
177 | return desc_sw; | 244 | return desc_sw; |
178 | } | 245 | } |
179 | 246 | ||
180 | #define INITIAL_IOAT_DESC_COUNT 128 | ||
181 | |||
182 | static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan); | ||
183 | |||
184 | /* returns the actual number of allocated descriptors */ | 247 | /* returns the actual number of allocated descriptors */ |
185 | static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) | 248 | static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) |
186 | { | 249 | { |
@@ -195,15 +258,16 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) | |||
195 | if (!list_empty(&ioat_chan->free_desc)) | 258 | if (!list_empty(&ioat_chan->free_desc)) |
196 | return INITIAL_IOAT_DESC_COUNT; | 259 | return INITIAL_IOAT_DESC_COUNT; |
197 | 260 | ||
198 | /* Setup register to interrupt and write completion status on error */ | 261 | /* Setup register to interrupt and write completion status on error */ |
199 | chanctrl = IOAT_CHANCTRL_ERR_INT_EN | | 262 | chanctrl = IOAT_CHANCTRL_ERR_INT_EN | |
200 | IOAT_CHANCTRL_ANY_ERR_ABORT_EN | | 263 | IOAT_CHANCTRL_ANY_ERR_ABORT_EN | |
201 | IOAT_CHANCTRL_ERR_COMPLETION_EN; | 264 | IOAT_CHANCTRL_ERR_COMPLETION_EN; |
202 | writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET); | 265 | writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET); |
203 | 266 | ||
204 | chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET); | 267 | chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET); |
205 | if (chanerr) { | 268 | if (chanerr) { |
206 | printk("IOAT: CHANERR = %x, clearing\n", chanerr); | 269 | dev_err(&ioat_chan->device->pdev->dev, |
270 | "ioatdma: CHANERR = %x, clearing\n", chanerr); | ||
207 | writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET); | 271 | writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET); |
208 | } | 272 | } |
209 | 273 | ||
@@ -211,7 +275,8 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) | |||
211 | for (i = 0; i < INITIAL_IOAT_DESC_COUNT; i++) { | 275 | for (i = 0; i < INITIAL_IOAT_DESC_COUNT; i++) { |
212 | desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL); | 276 | desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL); |
213 | if (!desc) { | 277 | if (!desc) { |
214 | printk(KERN_ERR "IOAT: Only %d initial descriptors\n", i); | 278 | dev_err(&ioat_chan->device->pdev->dev, |
279 | "ioatdma: Only %d initial descriptors\n", i); | ||
215 | break; | 280 | break; |
216 | } | 281 | } |
217 | list_add_tail(&desc->node, &tmp_list); | 282 | list_add_tail(&desc->node, &tmp_list); |
@@ -224,8 +289,8 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) | |||
224 | /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ | 289 | /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ |
225 | ioat_chan->completion_virt = | 290 | ioat_chan->completion_virt = |
226 | pci_pool_alloc(ioat_chan->device->completion_pool, | 291 | pci_pool_alloc(ioat_chan->device->completion_pool, |
227 | GFP_KERNEL, | 292 | GFP_KERNEL, |
228 | &ioat_chan->completion_addr); | 293 | &ioat_chan->completion_addr); |
229 | memset(ioat_chan->completion_virt, 0, | 294 | memset(ioat_chan->completion_virt, 0, |
230 | sizeof(*ioat_chan->completion_virt)); | 295 | sizeof(*ioat_chan->completion_virt)); |
231 | writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF, | 296 | writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF, |
@@ -233,54 +298,88 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) | |||
233 | writel(((u64) ioat_chan->completion_addr) >> 32, | 298 | writel(((u64) ioat_chan->completion_addr) >> 32, |
234 | ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); | 299 | ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); |
235 | 300 | ||
236 | ioat_start_null_desc(ioat_chan); | 301 | tasklet_enable(&ioat_chan->cleanup_task); |
302 | ioat_dma_start_null_desc(ioat_chan); | ||
237 | return i; | 303 | return i; |
238 | } | 304 | } |
239 | 305 | ||
240 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); | ||
241 | |||
242 | static void ioat_dma_free_chan_resources(struct dma_chan *chan) | 306 | static void ioat_dma_free_chan_resources(struct dma_chan *chan) |
243 | { | 307 | { |
244 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); | 308 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); |
245 | struct ioat_device *ioat_device = to_ioat_device(chan->device); | 309 | struct ioatdma_device *ioatdma_device = to_ioatdma_device(chan->device); |
246 | struct ioat_desc_sw *desc, *_desc; | 310 | struct ioat_desc_sw *desc, *_desc; |
247 | u16 chanctrl; | ||
248 | int in_use_descs = 0; | 311 | int in_use_descs = 0; |
249 | 312 | ||
313 | tasklet_disable(&ioat_chan->cleanup_task); | ||
250 | ioat_dma_memcpy_cleanup(ioat_chan); | 314 | ioat_dma_memcpy_cleanup(ioat_chan); |
251 | 315 | ||
316 | /* Delay 100ms after reset to allow internal DMA logic to quiesce | ||
317 | * before removing DMA descriptor resources. | ||
318 | */ | ||
252 | writeb(IOAT_CHANCMD_RESET, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); | 319 | writeb(IOAT_CHANCMD_RESET, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); |
320 | mdelay(100); | ||
253 | 321 | ||
254 | spin_lock_bh(&ioat_chan->desc_lock); | 322 | spin_lock_bh(&ioat_chan->desc_lock); |
255 | list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) { | 323 | list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) { |
256 | in_use_descs++; | 324 | in_use_descs++; |
257 | list_del(&desc->node); | 325 | list_del(&desc->node); |
258 | pci_pool_free(ioat_device->dma_pool, desc->hw, | 326 | pci_pool_free(ioatdma_device->dma_pool, desc->hw, |
259 | desc->async_tx.phys); | 327 | desc->async_tx.phys); |
260 | kfree(desc); | 328 | kfree(desc); |
261 | } | 329 | } |
262 | list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) { | 330 | list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) { |
263 | list_del(&desc->node); | 331 | list_del(&desc->node); |
264 | pci_pool_free(ioat_device->dma_pool, desc->hw, | 332 | pci_pool_free(ioatdma_device->dma_pool, desc->hw, |
265 | desc->async_tx.phys); | 333 | desc->async_tx.phys); |
266 | kfree(desc); | 334 | kfree(desc); |
267 | } | 335 | } |
268 | spin_unlock_bh(&ioat_chan->desc_lock); | 336 | spin_unlock_bh(&ioat_chan->desc_lock); |
269 | 337 | ||
270 | pci_pool_free(ioat_device->completion_pool, | 338 | pci_pool_free(ioatdma_device->completion_pool, |
271 | ioat_chan->completion_virt, | 339 | ioat_chan->completion_virt, |
272 | ioat_chan->completion_addr); | 340 | ioat_chan->completion_addr); |
273 | 341 | ||
274 | /* one is ok since we left it on there on purpose */ | 342 | /* one is ok since we left it on there on purpose */ |
275 | if (in_use_descs > 1) | 343 | if (in_use_descs > 1) |
276 | printk(KERN_ERR "IOAT: Freeing %d in use descriptors!\n", | 344 | dev_err(&ioat_chan->device->pdev->dev, |
345 | "ioatdma: Freeing %d in use descriptors!\n", | ||
277 | in_use_descs - 1); | 346 | in_use_descs - 1); |
278 | 347 | ||
279 | ioat_chan->last_completion = ioat_chan->completion_addr = 0; | 348 | ioat_chan->last_completion = ioat_chan->completion_addr = 0; |
349 | ioat_chan->pending = 0; | ||
350 | } | ||
351 | /** | ||
352 | * ioat_dma_get_next_descriptor - return the next available descriptor | ||
353 | * @ioat_chan: IOAT DMA channel handle | ||
354 | * | ||
355 | * Gets the next descriptor from the chain, and must be called with the | ||
356 | * channel's desc_lock held. Allocates more descriptors if the channel | ||
357 | * has run out. | ||
358 | */ | ||
359 | static struct ioat_desc_sw *ioat_dma_get_next_descriptor( | ||
360 | struct ioat_dma_chan *ioat_chan) | ||
361 | { | ||
362 | struct ioat_desc_sw *new = NULL; | ||
363 | |||
364 | if (!list_empty(&ioat_chan->free_desc)) { | ||
365 | new = to_ioat_desc(ioat_chan->free_desc.next); | ||
366 | list_del(&new->node); | ||
367 | } else { | ||
368 | /* try to get another desc */ | ||
369 | new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); | ||
370 | /* will this ever happen? */ | ||
371 | /* TODO add upper limit on these */ | ||
372 | BUG_ON(!new); | ||
373 | } | ||
374 | |||
375 | prefetch(new->hw); | ||
376 | return new; | ||
280 | } | 377 | } |
281 | 378 | ||
282 | static struct dma_async_tx_descriptor * | 379 | static struct dma_async_tx_descriptor *ioat_dma_prep_memcpy( |
283 | ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) | 380 | struct dma_chan *chan, |
381 | size_t len, | ||
382 | int int_en) | ||
284 | { | 383 | { |
285 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); | 384 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); |
286 | struct ioat_desc_sw *first, *prev, *new; | 385 | struct ioat_desc_sw *first, *prev, *new; |
@@ -299,17 +398,7 @@ ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) | |||
299 | 398 | ||
300 | spin_lock_bh(&ioat_chan->desc_lock); | 399 | spin_lock_bh(&ioat_chan->desc_lock); |
301 | while (len) { | 400 | while (len) { |
302 | if (!list_empty(&ioat_chan->free_desc)) { | 401 | new = ioat_dma_get_next_descriptor(ioat_chan); |
303 | new = to_ioat_desc(ioat_chan->free_desc.next); | ||
304 | list_del(&new->node); | ||
305 | } else { | ||
306 | /* try to get another desc */ | ||
307 | new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); | ||
308 | /* will this ever happen? */ | ||
309 | /* TODO add upper limit on these */ | ||
310 | BUG_ON(!new); | ||
311 | } | ||
312 | |||
313 | copy = min((u32) len, ioat_chan->xfercap); | 402 | copy = min((u32) len, ioat_chan->xfercap); |
314 | 403 | ||
315 | new->hw->size = copy; | 404 | new->hw->size = copy; |
@@ -343,12 +432,11 @@ ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) | |||
343 | return new ? &new->async_tx : NULL; | 432 | return new ? &new->async_tx : NULL; |
344 | } | 433 | } |
345 | 434 | ||
346 | |||
347 | /** | 435 | /** |
348 | * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended descriptors to hw | 436 | * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended |
437 | * descriptors to hw | ||
349 | * @chan: DMA channel handle | 438 | * @chan: DMA channel handle |
350 | */ | 439 | */ |
351 | |||
352 | static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan) | 440 | static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan) |
353 | { | 441 | { |
354 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); | 442 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); |
@@ -360,15 +448,23 @@ static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan) | |||
360 | } | 448 | } |
361 | } | 449 | } |
362 | 450 | ||
363 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) | 451 | static void ioat_dma_cleanup_tasklet(unsigned long data) |
452 | { | ||
453 | struct ioat_dma_chan *chan = (void *)data; | ||
454 | ioat_dma_memcpy_cleanup(chan); | ||
455 | writew(IOAT_CHANCTRL_INT_DISABLE, | ||
456 | chan->reg_base + IOAT_CHANCTRL_OFFSET); | ||
457 | } | ||
458 | |||
459 | static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) | ||
364 | { | 460 | { |
365 | unsigned long phys_complete; | 461 | unsigned long phys_complete; |
366 | struct ioat_desc_sw *desc, *_desc; | 462 | struct ioat_desc_sw *desc, *_desc; |
367 | dma_cookie_t cookie = 0; | 463 | dma_cookie_t cookie = 0; |
368 | 464 | ||
369 | prefetch(chan->completion_virt); | 465 | prefetch(ioat_chan->completion_virt); |
370 | 466 | ||
371 | if (!spin_trylock(&chan->cleanup_lock)) | 467 | if (!spin_trylock(&ioat_chan->cleanup_lock)) |
372 | return; | 468 | return; |
373 | 469 | ||
374 | /* The completion writeback can happen at any time, | 470 | /* The completion writeback can happen at any time, |
@@ -378,26 +474,28 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) | |||
378 | 474 | ||
379 | #if (BITS_PER_LONG == 64) | 475 | #if (BITS_PER_LONG == 64) |
380 | phys_complete = | 476 | phys_complete = |
381 | chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR; | 477 | ioat_chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR; |
382 | #else | 478 | #else |
383 | phys_complete = chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK; | 479 | phys_complete = ioat_chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK; |
384 | #endif | 480 | #endif |
385 | 481 | ||
386 | if ((chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) == | 482 | if ((ioat_chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) == |
387 | IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) { | 483 | IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) { |
388 | printk("IOAT: Channel halted, chanerr = %x\n", | 484 | dev_err(&ioat_chan->device->pdev->dev, |
389 | readl(chan->reg_base + IOAT_CHANERR_OFFSET)); | 485 | "ioatdma: Channel halted, chanerr = %x\n", |
486 | readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET)); | ||
390 | 487 | ||
391 | /* TODO do something to salvage the situation */ | 488 | /* TODO do something to salvage the situation */ |
392 | } | 489 | } |
393 | 490 | ||
394 | if (phys_complete == chan->last_completion) { | 491 | if (phys_complete == ioat_chan->last_completion) { |
395 | spin_unlock(&chan->cleanup_lock); | 492 | spin_unlock(&ioat_chan->cleanup_lock); |
396 | return; | 493 | return; |
397 | } | 494 | } |
398 | 495 | ||
399 | spin_lock_bh(&chan->desc_lock); | 496 | cookie = 0; |
400 | list_for_each_entry_safe(desc, _desc, &chan->used_desc, node) { | 497 | spin_lock_bh(&ioat_chan->desc_lock); |
498 | list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) { | ||
401 | 499 | ||
402 | /* | 500 | /* |
403 | * Incoming DMA requests may use multiple descriptors, due to | 501 | * Incoming DMA requests may use multiple descriptors, due to |
@@ -407,31 +505,36 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) | |||
407 | if (desc->async_tx.cookie) { | 505 | if (desc->async_tx.cookie) { |
408 | cookie = desc->async_tx.cookie; | 506 | cookie = desc->async_tx.cookie; |
409 | 507 | ||
410 | /* yes we are unmapping both _page and _single alloc'd | 508 | /* |
411 | regions with unmap_page. Is this *really* that bad? | 509 | * yes we are unmapping both _page and _single alloc'd |
412 | */ | 510 | * regions with unmap_page. Is this *really* that bad? |
413 | pci_unmap_page(chan->device->pdev, | 511 | */ |
512 | pci_unmap_page(ioat_chan->device->pdev, | ||
414 | pci_unmap_addr(desc, dst), | 513 | pci_unmap_addr(desc, dst), |
415 | pci_unmap_len(desc, len), | 514 | pci_unmap_len(desc, len), |
416 | PCI_DMA_FROMDEVICE); | 515 | PCI_DMA_FROMDEVICE); |
417 | pci_unmap_page(chan->device->pdev, | 516 | pci_unmap_page(ioat_chan->device->pdev, |
418 | pci_unmap_addr(desc, src), | 517 | pci_unmap_addr(desc, src), |
419 | pci_unmap_len(desc, len), | 518 | pci_unmap_len(desc, len), |
420 | PCI_DMA_TODEVICE); | 519 | PCI_DMA_TODEVICE); |
421 | } | 520 | } |
422 | 521 | ||
423 | if (desc->async_tx.phys != phys_complete) { | 522 | if (desc->async_tx.phys != phys_complete) { |
424 | /* a completed entry, but not the last, so cleanup | 523 | /* |
524 | * a completed entry, but not the last, so cleanup | ||
425 | * if the client is done with the descriptor | 525 | * if the client is done with the descriptor |
426 | */ | 526 | */ |
427 | if (desc->async_tx.ack) { | 527 | if (desc->async_tx.ack) { |
428 | list_del(&desc->node); | 528 | list_del(&desc->node); |
429 | list_add_tail(&desc->node, &chan->free_desc); | 529 | list_add_tail(&desc->node, |
530 | &ioat_chan->free_desc); | ||
430 | } else | 531 | } else |
431 | desc->async_tx.cookie = 0; | 532 | desc->async_tx.cookie = 0; |
432 | } else { | 533 | } else { |
433 | /* last used desc. Do not remove, so we can append from | 534 | /* |
434 | it, but don't look at it next time, either */ | 535 | * last used desc. Do not remove, so we can append from |
536 | * it, but don't look at it next time, either | ||
537 | */ | ||
435 | desc->async_tx.cookie = 0; | 538 | desc->async_tx.cookie = 0; |
436 | 539 | ||
437 | /* TODO check status bits? */ | 540 | /* TODO check status bits? */ |
@@ -439,13 +542,13 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) | |||
439 | } | 542 | } |
440 | } | 543 | } |
441 | 544 | ||
442 | spin_unlock_bh(&chan->desc_lock); | 545 | spin_unlock_bh(&ioat_chan->desc_lock); |
443 | 546 | ||
444 | chan->last_completion = phys_complete; | 547 | ioat_chan->last_completion = phys_complete; |
445 | if (cookie != 0) | 548 | if (cookie != 0) |
446 | chan->completed_cookie = cookie; | 549 | ioat_chan->completed_cookie = cookie; |
447 | 550 | ||
448 | spin_unlock(&chan->cleanup_lock); | 551 | spin_unlock(&ioat_chan->cleanup_lock); |
449 | } | 552 | } |
450 | 553 | ||
451 | static void ioat_dma_dependency_added(struct dma_chan *chan) | 554 | static void ioat_dma_dependency_added(struct dma_chan *chan) |
@@ -466,11 +569,10 @@ static void ioat_dma_dependency_added(struct dma_chan *chan) | |||
466 | * @done: if not %NULL, updated with last completed transaction | 569 | * @done: if not %NULL, updated with last completed transaction |
467 | * @used: if not %NULL, updated with last used transaction | 570 | * @used: if not %NULL, updated with last used transaction |
468 | */ | 571 | */ |
469 | |||
470 | static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, | 572 | static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, |
471 | dma_cookie_t cookie, | 573 | dma_cookie_t cookie, |
472 | dma_cookie_t *done, | 574 | dma_cookie_t *done, |
473 | dma_cookie_t *used) | 575 | dma_cookie_t *used) |
474 | { | 576 | { |
475 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); | 577 | struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); |
476 | dma_cookie_t last_used; | 578 | dma_cookie_t last_used; |
@@ -481,7 +583,7 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, | |||
481 | last_complete = ioat_chan->completed_cookie; | 583 | last_complete = ioat_chan->completed_cookie; |
482 | 584 | ||
483 | if (done) | 585 | if (done) |
484 | *done= last_complete; | 586 | *done = last_complete; |
485 | if (used) | 587 | if (used) |
486 | *used = last_used; | 588 | *used = last_used; |
487 | 589 | ||
@@ -495,7 +597,7 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, | |||
495 | last_complete = ioat_chan->completed_cookie; | 597 | last_complete = ioat_chan->completed_cookie; |
496 | 598 | ||
497 | if (done) | 599 | if (done) |
498 | *done= last_complete; | 600 | *done = last_complete; |
499 | if (used) | 601 | if (used) |
500 | *used = last_used; | 602 | *used = last_used; |
501 | 603 | ||
@@ -504,63 +606,13 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, | |||
504 | 606 | ||
505 | /* PCI API */ | 607 | /* PCI API */ |
506 | 608 | ||
507 | static struct pci_device_id ioat_pci_tbl[] = { | 609 | static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) |
508 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) }, | ||
509 | { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, | ||
510 | PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) }, | ||
511 | { 0, } | ||
512 | }; | ||
513 | |||
514 | static struct pci_driver ioat_pci_driver = { | ||
515 | .name = "ioatdma", | ||
516 | .id_table = ioat_pci_tbl, | ||
517 | .probe = ioat_probe, | ||
518 | .shutdown = ioat_shutdown, | ||
519 | .remove = __devexit_p(ioat_remove), | ||
520 | }; | ||
521 | |||
522 | static irqreturn_t ioat_do_interrupt(int irq, void *data) | ||
523 | { | ||
524 | struct ioat_device *instance = data; | ||
525 | unsigned long attnstatus; | ||
526 | u8 intrctrl; | ||
527 | |||
528 | intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
529 | |||
530 | if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN)) | ||
531 | return IRQ_NONE; | ||
532 | |||
533 | if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) { | ||
534 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
535 | return IRQ_NONE; | ||
536 | } | ||
537 | |||
538 | attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); | ||
539 | |||
540 | printk(KERN_ERR "ioatdma error: interrupt! status %lx\n", attnstatus); | ||
541 | |||
542 | writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); | ||
543 | return IRQ_HANDLED; | ||
544 | } | ||
545 | |||
546 | static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan) | ||
547 | { | 610 | { |
548 | struct ioat_desc_sw *desc; | 611 | struct ioat_desc_sw *desc; |
549 | 612 | ||
550 | spin_lock_bh(&ioat_chan->desc_lock); | 613 | spin_lock_bh(&ioat_chan->desc_lock); |
551 | 614 | ||
552 | if (!list_empty(&ioat_chan->free_desc)) { | 615 | desc = ioat_dma_get_next_descriptor(ioat_chan); |
553 | desc = to_ioat_desc(ioat_chan->free_desc.next); | ||
554 | list_del(&desc->node); | ||
555 | } else { | ||
556 | /* try to get another desc */ | ||
557 | spin_unlock_bh(&ioat_chan->desc_lock); | ||
558 | desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL); | ||
559 | spin_lock_bh(&ioat_chan->desc_lock); | ||
560 | /* will this ever happen? */ | ||
561 | BUG_ON(!desc); | ||
562 | } | ||
563 | |||
564 | desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL; | 616 | desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL; |
565 | desc->hw->next = 0; | 617 | desc->hw->next = 0; |
566 | desc->async_tx.ack = 1; | 618 | desc->async_tx.ack = 1; |
@@ -581,7 +633,11 @@ static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan) | |||
581 | */ | 633 | */ |
582 | #define IOAT_TEST_SIZE 2000 | 634 | #define IOAT_TEST_SIZE 2000 |
583 | 635 | ||
584 | static int ioat_self_test(struct ioat_device *device) | 636 | /** |
637 | * ioat_dma_self_test - Perform a IOAT transaction to verify the HW works. | ||
638 | * @device: device to be tested | ||
639 | */ | ||
640 | static int ioat_dma_self_test(struct ioatdma_device *device) | ||
585 | { | 641 | { |
586 | int i; | 642 | int i; |
587 | u8 *src; | 643 | u8 *src; |
@@ -607,9 +663,11 @@ static int ioat_self_test(struct ioat_device *device) | |||
607 | 663 | ||
608 | /* Start copy, using first DMA channel */ | 664 | /* Start copy, using first DMA channel */ |
609 | dma_chan = container_of(device->common.channels.next, | 665 | dma_chan = container_of(device->common.channels.next, |
610 | struct dma_chan, | 666 | struct dma_chan, |
611 | device_node); | 667 | device_node); |
612 | if (ioat_dma_alloc_chan_resources(dma_chan) < 1) { | 668 | if (ioat_dma_alloc_chan_resources(dma_chan) < 1) { |
669 | dev_err(&device->pdev->dev, | ||
670 | "selftest cannot allocate chan resource\n"); | ||
613 | err = -ENODEV; | 671 | err = -ENODEV; |
614 | goto out; | 672 | goto out; |
615 | } | 673 | } |
@@ -627,12 +685,14 @@ static int ioat_self_test(struct ioat_device *device) | |||
627 | msleep(1); | 685 | msleep(1); |
628 | 686 | ||
629 | if (ioat_dma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { | 687 | if (ioat_dma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { |
630 | printk(KERN_ERR "ioatdma: Self-test copy timed out, disabling\n"); | 688 | dev_err(&device->pdev->dev, |
689 | "ioatdma: Self-test copy timed out, disabling\n"); | ||
631 | err = -ENODEV; | 690 | err = -ENODEV; |
632 | goto free_resources; | 691 | goto free_resources; |
633 | } | 692 | } |
634 | if (memcmp(src, dest, IOAT_TEST_SIZE)) { | 693 | if (memcmp(src, dest, IOAT_TEST_SIZE)) { |
635 | printk(KERN_ERR "ioatdma: Self-test copy failed compare, disabling\n"); | 694 | dev_err(&device->pdev->dev, |
695 | "ioatdma: Self-test copy failed compare, disabling\n"); | ||
636 | err = -ENODEV; | 696 | err = -ENODEV; |
637 | goto free_resources; | 697 | goto free_resources; |
638 | } | 698 | } |
@@ -645,147 +705,252 @@ out: | |||
645 | return err; | 705 | return err; |
646 | } | 706 | } |
647 | 707 | ||
648 | static int __devinit ioat_probe(struct pci_dev *pdev, | 708 | static char ioat_interrupt_style[32] = "msix"; |
649 | const struct pci_device_id *ent) | 709 | module_param_string(ioat_interrupt_style, ioat_interrupt_style, |
710 | sizeof(ioat_interrupt_style), 0644); | ||
711 | MODULE_PARM_DESC(ioat_interrupt_style, | ||
712 | "set ioat interrupt style: msix (default), " | ||
713 | "msix-single-vector, msi, intx)"); | ||
714 | |||
715 | /** | ||
716 | * ioat_dma_setup_interrupts - setup interrupt handler | ||
717 | * @device: ioat device | ||
718 | */ | ||
719 | static int ioat_dma_setup_interrupts(struct ioatdma_device *device) | ||
650 | { | 720 | { |
651 | int err; | 721 | struct ioat_dma_chan *ioat_chan; |
652 | unsigned long mmio_start, mmio_len; | 722 | int err, i, j, msixcnt; |
653 | void __iomem *reg_base; | 723 | u8 intrctrl = 0; |
654 | struct ioat_device *device; | 724 | |
725 | if (!strcmp(ioat_interrupt_style, "msix")) | ||
726 | goto msix; | ||
727 | if (!strcmp(ioat_interrupt_style, "msix-single-vector")) | ||
728 | goto msix_single_vector; | ||
729 | if (!strcmp(ioat_interrupt_style, "msi")) | ||
730 | goto msi; | ||
731 | if (!strcmp(ioat_interrupt_style, "intx")) | ||
732 | goto intx; | ||
733 | |||
734 | msix: | ||
735 | /* The number of MSI-X vectors should equal the number of channels */ | ||
736 | msixcnt = device->common.chancnt; | ||
737 | for (i = 0; i < msixcnt; i++) | ||
738 | device->msix_entries[i].entry = i; | ||
739 | |||
740 | err = pci_enable_msix(device->pdev, device->msix_entries, msixcnt); | ||
741 | if (err < 0) | ||
742 | goto msi; | ||
743 | if (err > 0) | ||
744 | goto msix_single_vector; | ||
745 | |||
746 | for (i = 0; i < msixcnt; i++) { | ||
747 | ioat_chan = ioat_lookup_chan_by_index(device, i); | ||
748 | err = request_irq(device->msix_entries[i].vector, | ||
749 | ioat_dma_do_interrupt_msix, | ||
750 | 0, "ioat-msix", ioat_chan); | ||
751 | if (err) { | ||
752 | for (j = 0; j < i; j++) { | ||
753 | ioat_chan = | ||
754 | ioat_lookup_chan_by_index(device, j); | ||
755 | free_irq(device->msix_entries[j].vector, | ||
756 | ioat_chan); | ||
757 | } | ||
758 | goto msix_single_vector; | ||
759 | } | ||
760 | } | ||
761 | intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL; | ||
762 | device->irq_mode = msix_multi_vector; | ||
763 | goto done; | ||
655 | 764 | ||
656 | err = pci_enable_device(pdev); | 765 | msix_single_vector: |
766 | device->msix_entries[0].entry = 0; | ||
767 | err = pci_enable_msix(device->pdev, device->msix_entries, 1); | ||
657 | if (err) | 768 | if (err) |
658 | goto err_enable_device; | 769 | goto msi; |
659 | 770 | ||
660 | err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | 771 | err = request_irq(device->msix_entries[0].vector, ioat_dma_do_interrupt, |
661 | if (err) | 772 | 0, "ioat-msix", device); |
662 | err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | 773 | if (err) { |
774 | pci_disable_msix(device->pdev); | ||
775 | goto msi; | ||
776 | } | ||
777 | device->irq_mode = msix_single_vector; | ||
778 | goto done; | ||
779 | |||
780 | msi: | ||
781 | err = pci_enable_msi(device->pdev); | ||
663 | if (err) | 782 | if (err) |
664 | goto err_set_dma_mask; | 783 | goto intx; |
665 | 784 | ||
666 | err = pci_request_regions(pdev, ioat_pci_driver.name); | 785 | err = request_irq(device->pdev->irq, ioat_dma_do_interrupt, |
786 | 0, "ioat-msi", device); | ||
787 | if (err) { | ||
788 | pci_disable_msi(device->pdev); | ||
789 | goto intx; | ||
790 | } | ||
791 | /* | ||
792 | * CB 1.2 devices need a bit set in configuration space to enable MSI | ||
793 | */ | ||
794 | if (device->version == IOAT_VER_1_2) { | ||
795 | u32 dmactrl; | ||
796 | pci_read_config_dword(device->pdev, | ||
797 | IOAT_PCI_DMACTRL_OFFSET, &dmactrl); | ||
798 | dmactrl |= IOAT_PCI_DMACTRL_MSI_EN; | ||
799 | pci_write_config_dword(device->pdev, | ||
800 | IOAT_PCI_DMACTRL_OFFSET, dmactrl); | ||
801 | } | ||
802 | device->irq_mode = msi; | ||
803 | goto done; | ||
804 | |||
805 | intx: | ||
806 | err = request_irq(device->pdev->irq, ioat_dma_do_interrupt, | ||
807 | IRQF_SHARED, "ioat-intx", device); | ||
667 | if (err) | 808 | if (err) |
668 | goto err_request_regions; | 809 | goto err_no_irq; |
810 | device->irq_mode = intx; | ||
669 | 811 | ||
670 | mmio_start = pci_resource_start(pdev, 0); | 812 | done: |
671 | mmio_len = pci_resource_len(pdev, 0); | 813 | intrctrl |= IOAT_INTRCTRL_MASTER_INT_EN; |
814 | writeb(intrctrl, device->reg_base + IOAT_INTRCTRL_OFFSET); | ||
815 | return 0; | ||
672 | 816 | ||
673 | reg_base = ioremap(mmio_start, mmio_len); | 817 | err_no_irq: |
674 | if (!reg_base) { | 818 | /* Disable all interrupt generation */ |
675 | err = -ENOMEM; | 819 | writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET); |
676 | goto err_ioremap; | 820 | dev_err(&device->pdev->dev, "no usable interrupts\n"); |
821 | device->irq_mode = none; | ||
822 | return -1; | ||
823 | } | ||
824 | |||
825 | /** | ||
826 | * ioat_dma_remove_interrupts - remove whatever interrupts were set | ||
827 | * @device: ioat device | ||
828 | */ | ||
829 | static void ioat_dma_remove_interrupts(struct ioatdma_device *device) | ||
830 | { | ||
831 | struct ioat_dma_chan *ioat_chan; | ||
832 | int i; | ||
833 | |||
834 | /* Disable all interrupt generation */ | ||
835 | writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET); | ||
836 | |||
837 | switch (device->irq_mode) { | ||
838 | case msix_multi_vector: | ||
839 | for (i = 0; i < device->common.chancnt; i++) { | ||
840 | ioat_chan = ioat_lookup_chan_by_index(device, i); | ||
841 | free_irq(device->msix_entries[i].vector, ioat_chan); | ||
842 | } | ||
843 | pci_disable_msix(device->pdev); | ||
844 | break; | ||
845 | case msix_single_vector: | ||
846 | free_irq(device->msix_entries[0].vector, device); | ||
847 | pci_disable_msix(device->pdev); | ||
848 | break; | ||
849 | case msi: | ||
850 | free_irq(device->pdev->irq, device); | ||
851 | pci_disable_msi(device->pdev); | ||
852 | break; | ||
853 | case intx: | ||
854 | free_irq(device->pdev->irq, device); | ||
855 | break; | ||
856 | case none: | ||
857 | dev_warn(&device->pdev->dev, | ||
858 | "call to %s without interrupts setup\n", __func__); | ||
677 | } | 859 | } |
860 | device->irq_mode = none; | ||
861 | } | ||
862 | |||
863 | struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, | ||
864 | void __iomem *iobase) | ||
865 | { | ||
866 | int err; | ||
867 | struct ioatdma_device *device; | ||
678 | 868 | ||
679 | device = kzalloc(sizeof(*device), GFP_KERNEL); | 869 | device = kzalloc(sizeof(*device), GFP_KERNEL); |
680 | if (!device) { | 870 | if (!device) { |
681 | err = -ENOMEM; | 871 | err = -ENOMEM; |
682 | goto err_kzalloc; | 872 | goto err_kzalloc; |
683 | } | 873 | } |
874 | device->pdev = pdev; | ||
875 | device->reg_base = iobase; | ||
876 | device->version = readb(device->reg_base + IOAT_VER_OFFSET); | ||
684 | 877 | ||
685 | /* DMA coherent memory pool for DMA descriptor allocations */ | 878 | /* DMA coherent memory pool for DMA descriptor allocations */ |
686 | device->dma_pool = pci_pool_create("dma_desc_pool", pdev, | 879 | device->dma_pool = pci_pool_create("dma_desc_pool", pdev, |
687 | sizeof(struct ioat_dma_descriptor), 64, 0); | 880 | sizeof(struct ioat_dma_descriptor), |
881 | 64, 0); | ||
688 | if (!device->dma_pool) { | 882 | if (!device->dma_pool) { |
689 | err = -ENOMEM; | 883 | err = -ENOMEM; |
690 | goto err_dma_pool; | 884 | goto err_dma_pool; |
691 | } | 885 | } |
692 | 886 | ||
693 | device->completion_pool = pci_pool_create("completion_pool", pdev, sizeof(u64), SMP_CACHE_BYTES, SMP_CACHE_BYTES); | 887 | device->completion_pool = pci_pool_create("completion_pool", pdev, |
888 | sizeof(u64), SMP_CACHE_BYTES, | ||
889 | SMP_CACHE_BYTES); | ||
694 | if (!device->completion_pool) { | 890 | if (!device->completion_pool) { |
695 | err = -ENOMEM; | 891 | err = -ENOMEM; |
696 | goto err_completion_pool; | 892 | goto err_completion_pool; |
697 | } | 893 | } |
698 | 894 | ||
699 | device->pdev = pdev; | ||
700 | pci_set_drvdata(pdev, device); | ||
701 | #ifdef CONFIG_PCI_MSI | ||
702 | if (pci_enable_msi(pdev) == 0) { | ||
703 | device->msi = 1; | ||
704 | } else { | ||
705 | device->msi = 0; | ||
706 | } | ||
707 | #endif | ||
708 | err = request_irq(pdev->irq, &ioat_do_interrupt, IRQF_SHARED, "ioat", | ||
709 | device); | ||
710 | if (err) | ||
711 | goto err_irq; | ||
712 | |||
713 | device->reg_base = reg_base; | ||
714 | |||
715 | writeb(IOAT_INTRCTRL_MASTER_INT_EN, device->reg_base + IOAT_INTRCTRL_OFFSET); | ||
716 | pci_set_master(pdev); | ||
717 | |||
718 | INIT_LIST_HEAD(&device->common.channels); | 895 | INIT_LIST_HEAD(&device->common.channels); |
719 | enumerate_dma_channels(device); | 896 | ioat_dma_enumerate_channels(device); |
720 | 897 | ||
721 | dma_cap_set(DMA_MEMCPY, device->common.cap_mask); | 898 | dma_cap_set(DMA_MEMCPY, device->common.cap_mask); |
722 | device->common.device_alloc_chan_resources = ioat_dma_alloc_chan_resources; | 899 | device->common.device_alloc_chan_resources = |
723 | device->common.device_free_chan_resources = ioat_dma_free_chan_resources; | 900 | ioat_dma_alloc_chan_resources; |
901 | device->common.device_free_chan_resources = | ||
902 | ioat_dma_free_chan_resources; | ||
724 | device->common.device_prep_dma_memcpy = ioat_dma_prep_memcpy; | 903 | device->common.device_prep_dma_memcpy = ioat_dma_prep_memcpy; |
725 | device->common.device_is_tx_complete = ioat_dma_is_complete; | 904 | device->common.device_is_tx_complete = ioat_dma_is_complete; |
726 | device->common.device_issue_pending = ioat_dma_memcpy_issue_pending; | 905 | device->common.device_issue_pending = ioat_dma_memcpy_issue_pending; |
727 | device->common.device_dependency_added = ioat_dma_dependency_added; | 906 | device->common.device_dependency_added = ioat_dma_dependency_added; |
728 | device->common.dev = &pdev->dev; | 907 | device->common.dev = &pdev->dev; |
729 | printk(KERN_INFO "Intel(R) I/OAT DMA Engine found, %d channels\n", | 908 | dev_err(&device->pdev->dev, |
730 | device->common.chancnt); | 909 | "ioatdma: Intel(R) I/OAT DMA Engine found," |
910 | " %d channels, device version 0x%02x\n", | ||
911 | device->common.chancnt, device->version); | ||
731 | 912 | ||
732 | err = ioat_self_test(device); | 913 | err = ioat_dma_setup_interrupts(device); |
914 | if (err) | ||
915 | goto err_setup_interrupts; | ||
916 | |||
917 | err = ioat_dma_self_test(device); | ||
733 | if (err) | 918 | if (err) |
734 | goto err_self_test; | 919 | goto err_self_test; |
735 | 920 | ||
736 | dma_async_device_register(&device->common); | 921 | dma_async_device_register(&device->common); |
737 | 922 | ||
738 | return 0; | 923 | return device; |
739 | 924 | ||
740 | err_self_test: | 925 | err_self_test: |
741 | err_irq: | 926 | ioat_dma_remove_interrupts(device); |
927 | err_setup_interrupts: | ||
742 | pci_pool_destroy(device->completion_pool); | 928 | pci_pool_destroy(device->completion_pool); |
743 | err_completion_pool: | 929 | err_completion_pool: |
744 | pci_pool_destroy(device->dma_pool); | 930 | pci_pool_destroy(device->dma_pool); |
745 | err_dma_pool: | 931 | err_dma_pool: |
746 | kfree(device); | 932 | kfree(device); |
747 | err_kzalloc: | 933 | err_kzalloc: |
748 | iounmap(reg_base); | 934 | iounmap(iobase); |
749 | err_ioremap: | 935 | dev_err(&device->pdev->dev, |
750 | pci_release_regions(pdev); | 936 | "ioatdma: Intel(R) I/OAT DMA Engine initialization failed\n"); |
751 | err_request_regions: | 937 | return NULL; |
752 | err_set_dma_mask: | ||
753 | pci_disable_device(pdev); | ||
754 | err_enable_device: | ||
755 | |||
756 | printk(KERN_ERR "Intel(R) I/OAT DMA Engine initialization failed\n"); | ||
757 | |||
758 | return err; | ||
759 | } | 938 | } |
760 | 939 | ||
761 | static void ioat_shutdown(struct pci_dev *pdev) | 940 | void ioat_dma_remove(struct ioatdma_device *device) |
762 | { | 941 | { |
763 | struct ioat_device *device; | ||
764 | device = pci_get_drvdata(pdev); | ||
765 | |||
766 | dma_async_device_unregister(&device->common); | ||
767 | } | ||
768 | |||
769 | static void __devexit ioat_remove(struct pci_dev *pdev) | ||
770 | { | ||
771 | struct ioat_device *device; | ||
772 | struct dma_chan *chan, *_chan; | 942 | struct dma_chan *chan, *_chan; |
773 | struct ioat_dma_chan *ioat_chan; | 943 | struct ioat_dma_chan *ioat_chan; |
774 | 944 | ||
775 | device = pci_get_drvdata(pdev); | ||
776 | dma_async_device_unregister(&device->common); | 945 | dma_async_device_unregister(&device->common); |
777 | 946 | ||
778 | free_irq(device->pdev->irq, device); | 947 | ioat_dma_remove_interrupts(device); |
779 | #ifdef CONFIG_PCI_MSI | 948 | |
780 | if (device->msi) | ||
781 | pci_disable_msi(device->pdev); | ||
782 | #endif | ||
783 | pci_pool_destroy(device->dma_pool); | 949 | pci_pool_destroy(device->dma_pool); |
784 | pci_pool_destroy(device->completion_pool); | 950 | pci_pool_destroy(device->completion_pool); |
785 | iounmap(device->reg_base); | 951 | |
786 | pci_release_regions(pdev); | 952 | list_for_each_entry_safe(chan, _chan, |
787 | pci_disable_device(pdev); | 953 | &device->common.channels, device_node) { |
788 | list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) { | ||
789 | ioat_chan = to_ioat_chan(chan); | 954 | ioat_chan = to_ioat_chan(chan); |
790 | list_del(&chan->device_node); | 955 | list_del(&chan->device_node); |
791 | kfree(ioat_chan); | 956 | kfree(ioat_chan); |
@@ -793,25 +958,3 @@ static void __devexit ioat_remove(struct pci_dev *pdev) | |||
793 | kfree(device); | 958 | kfree(device); |
794 | } | 959 | } |
795 | 960 | ||
796 | /* MODULE API */ | ||
797 | MODULE_VERSION("1.9"); | ||
798 | MODULE_LICENSE("GPL"); | ||
799 | MODULE_AUTHOR("Intel Corporation"); | ||
800 | |||
801 | static int __init ioat_init_module(void) | ||
802 | { | ||
803 | /* it's currently unsafe to unload this module */ | ||
804 | /* if forced, worst case is that rmmod hangs */ | ||
805 | __unsafe(THIS_MODULE); | ||
806 | |||
807 | return pci_register_driver(&ioat_pci_driver); | ||
808 | } | ||
809 | |||
810 | module_init(ioat_init_module); | ||
811 | |||
812 | static void __exit ioat_exit_module(void) | ||
813 | { | ||
814 | pci_unregister_driver(&ioat_pci_driver); | ||
815 | } | ||
816 | |||
817 | module_exit(ioat_exit_module); | ||
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h index bf4dad70e0f5..2a319e124ece 100644 --- a/drivers/dma/ioatdma.h +++ b/drivers/dma/ioatdma.h | |||
@@ -28,25 +28,35 @@ | |||
28 | #include <linux/cache.h> | 28 | #include <linux/cache.h> |
29 | #include <linux/pci_ids.h> | 29 | #include <linux/pci_ids.h> |
30 | 30 | ||
31 | enum ioat_interrupt { | ||
32 | none = 0, | ||
33 | msix_multi_vector = 1, | ||
34 | msix_single_vector = 2, | ||
35 | msi = 3, | ||
36 | intx = 4, | ||
37 | }; | ||
38 | |||
31 | #define IOAT_LOW_COMPLETION_MASK 0xffffffc0 | 39 | #define IOAT_LOW_COMPLETION_MASK 0xffffffc0 |
32 | 40 | ||
33 | /** | 41 | /** |
34 | * struct ioat_device - internal representation of a IOAT device | 42 | * struct ioatdma_device - internal representation of a IOAT device |
35 | * @pdev: PCI-Express device | 43 | * @pdev: PCI-Express device |
36 | * @reg_base: MMIO register space base address | 44 | * @reg_base: MMIO register space base address |
37 | * @dma_pool: for allocating DMA descriptors | 45 | * @dma_pool: for allocating DMA descriptors |
38 | * @common: embedded struct dma_device | 46 | * @common: embedded struct dma_device |
39 | * @msi: Message Signaled Interrupt number | 47 | * @version: version of ioatdma device |
40 | */ | 48 | */ |
41 | 49 | ||
42 | struct ioat_device { | 50 | struct ioatdma_device { |
43 | struct pci_dev *pdev; | 51 | struct pci_dev *pdev; |
44 | void __iomem *reg_base; | 52 | void __iomem *reg_base; |
45 | struct pci_pool *dma_pool; | 53 | struct pci_pool *dma_pool; |
46 | struct pci_pool *completion_pool; | 54 | struct pci_pool *completion_pool; |
47 | |||
48 | struct dma_device common; | 55 | struct dma_device common; |
49 | u8 msi; | 56 | u8 version; |
57 | enum ioat_interrupt irq_mode; | ||
58 | struct msix_entry msix_entries[4]; | ||
59 | struct ioat_dma_chan *idx[4]; | ||
50 | }; | 60 | }; |
51 | 61 | ||
52 | /** | 62 | /** |
@@ -84,7 +94,7 @@ struct ioat_dma_chan { | |||
84 | 94 | ||
85 | int pending; | 95 | int pending; |
86 | 96 | ||
87 | struct ioat_device *device; | 97 | struct ioatdma_device *device; |
88 | struct dma_chan common; | 98 | struct dma_chan common; |
89 | 99 | ||
90 | dma_addr_t completion_addr; | 100 | dma_addr_t completion_addr; |
@@ -95,6 +105,7 @@ struct ioat_dma_chan { | |||
95 | u32 high; | 105 | u32 high; |
96 | }; | 106 | }; |
97 | } *completion_virt; | 107 | } *completion_virt; |
108 | struct tasklet_struct cleanup_task; | ||
98 | }; | 109 | }; |
99 | 110 | ||
100 | /* wrapper around hardware descriptor format + additional software fields */ | 111 | /* wrapper around hardware descriptor format + additional software fields */ |
@@ -117,4 +128,16 @@ struct ioat_desc_sw { | |||
117 | struct dma_async_tx_descriptor async_tx; | 128 | struct dma_async_tx_descriptor async_tx; |
118 | }; | 129 | }; |
119 | 130 | ||
131 | #if defined(CONFIG_INTEL_IOATDMA) || defined(CONFIG_INTEL_IOATDMA_MODULE) | ||
132 | struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, | ||
133 | void __iomem *iobase); | ||
134 | void ioat_dma_remove(struct ioatdma_device *device); | ||
135 | struct dca_provider *ioat_dca_init(struct pci_dev *pdev, | ||
136 | void __iomem *iobase); | ||
137 | #else | ||
138 | #define ioat_dma_probe(pdev, iobase) NULL | ||
139 | #define ioat_dma_remove(device) do { } while (0) | ||
140 | #define ioat_dca_init(pdev, iobase) NULL | ||
141 | #endif | ||
142 | |||
120 | #endif /* IOATDMA_H */ | 143 | #endif /* IOATDMA_H */ |
diff --git a/drivers/dma/ioatdma_hw.h b/drivers/dma/ioatdma_hw.h index 4d7a12880be3..9e7434e1551f 100644 --- a/drivers/dma/ioatdma_hw.h +++ b/drivers/dma/ioatdma_hw.h | |||
@@ -27,7 +27,7 @@ | |||
27 | #define IOAT_PCI_RID 0x00 | 27 | #define IOAT_PCI_RID 0x00 |
28 | #define IOAT_PCI_SVID 0x8086 | 28 | #define IOAT_PCI_SVID 0x8086 |
29 | #define IOAT_PCI_SID 0x8086 | 29 | #define IOAT_PCI_SID 0x8086 |
30 | #define IOAT_VER 0x12 /* Version 1.2 */ | 30 | #define IOAT_VER_1_2 0x12 /* Version 1.2 */ |
31 | 31 | ||
32 | struct ioat_dma_descriptor { | 32 | struct ioat_dma_descriptor { |
33 | uint32_t size; | 33 | uint32_t size; |
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h index a30c7349075a..baaab5ea146a 100644 --- a/drivers/dma/ioatdma_registers.h +++ b/drivers/dma/ioatdma_registers.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. | 2 | * Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the Free | 5 | * under the terms of the GNU General Public License as published by the Free |
@@ -21,6 +21,9 @@ | |||
21 | #ifndef _IOAT_REGISTERS_H_ | 21 | #ifndef _IOAT_REGISTERS_H_ |
22 | #define _IOAT_REGISTERS_H_ | 22 | #define _IOAT_REGISTERS_H_ |
23 | 23 | ||
24 | #define IOAT_PCI_DMACTRL_OFFSET 0x48 | ||
25 | #define IOAT_PCI_DMACTRL_DMA_EN 0x00000001 | ||
26 | #define IOAT_PCI_DMACTRL_MSI_EN 0x00000002 | ||
24 | 27 | ||
25 | /* MMIO Device Registers */ | 28 | /* MMIO Device Registers */ |
26 | #define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */ | 29 | #define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */ |
@@ -39,6 +42,7 @@ | |||
39 | #define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */ | 42 | #define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */ |
40 | #define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */ | 43 | #define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */ |
41 | #define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */ | 44 | #define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */ |
45 | #define IOAT_INTRCTRL_MSIX_VECTOR_CONTROL 0x08 /* Enable all MSI-X vectors */ | ||
42 | 46 | ||
43 | #define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */ | 47 | #define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */ |
44 | 48 | ||
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 23b6f7bc16b7..476012b6dfac 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c | |||
@@ -506,9 +506,14 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg) | |||
506 | { | 506 | { |
507 | struct sk_buff *skb; | 507 | struct sk_buff *skb; |
508 | size_t len; | 508 | size_t len; |
509 | |||
509 | capi_cmsg2message(cmsg, cmsg->buf); | 510 | capi_cmsg2message(cmsg, cmsg->buf); |
510 | len = CAPIMSG_LEN(cmsg->buf); | 511 | len = CAPIMSG_LEN(cmsg->buf); |
511 | skb = alloc_skb(len, GFP_ATOMIC); | 512 | skb = alloc_skb(len, GFP_ATOMIC); |
513 | if (!skb) { | ||
514 | printk(KERN_ERR "capidrv::send_message: can't allocate mem\n"); | ||
515 | return; | ||
516 | } | ||
512 | memcpy(skb_put(skb, len), cmsg->buf, len); | 517 | memcpy(skb_put(skb, len), cmsg->buf, len); |
513 | if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) | 518 | if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) |
514 | kfree_skb(skb); | 519 | kfree_skb(skb); |
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 9f73bc2727c2..f55531869313 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c | |||
@@ -821,6 +821,8 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) | |||
821 | return -EFAULT; | 821 | return -EFAULT; |
822 | } | 822 | } |
823 | card = get_capi_ctr_by_nr(ldef.contr); | 823 | card = get_capi_ctr_by_nr(ldef.contr); |
824 | if (!card) | ||
825 | return -EINVAL; | ||
824 | card = capi_ctr_get(card); | 826 | card = capi_ctr_get(card); |
825 | if (!card) | 827 | if (!card) |
826 | return -ESRCH; | 828 | return -ESRCH; |
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 00e31609a238..af7648274b38 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -1936,14 +1936,7 @@ static int gigaset_write_room(struct cardstate *cs) | |||
1936 | */ | 1936 | */ |
1937 | static int gigaset_chars_in_buffer(struct cardstate *cs) | 1937 | static int gigaset_chars_in_buffer(struct cardstate *cs) |
1938 | { | 1938 | { |
1939 | unsigned long flags; | 1939 | return cs->cmdbytes; |
1940 | unsigned bytes; | ||
1941 | |||
1942 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
1943 | bytes = cs->cmdbytes; | ||
1944 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
1945 | |||
1946 | return bytes; | ||
1947 | } | 1940 | } |
1948 | 1941 | ||
1949 | /* gigaset_brkchars | 1942 | /* gigaset_brkchars |
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 1654fa413575..9e089f06a942 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c | |||
@@ -109,13 +109,9 @@ EXPORT_SYMBOL_GPL(gigaset_skb_sent); | |||
109 | static int command_from_LL(isdn_ctrl *cntrl) | 109 | static int command_from_LL(isdn_ctrl *cntrl) |
110 | { | 110 | { |
111 | struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver); | 111 | struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver); |
112 | //isdn_ctrl response; | ||
113 | //unsigned long flags; | ||
114 | struct bc_state *bcs; | 112 | struct bc_state *bcs; |
115 | int retval = 0; | 113 | int retval = 0; |
116 | struct setup_parm *sp; | 114 | struct setup_parm *sp; |
117 | unsigned param; | ||
118 | unsigned long flags; | ||
119 | 115 | ||
120 | gigaset_debugdrivers(); | 116 | gigaset_debugdrivers(); |
121 | 117 | ||
@@ -162,12 +158,8 @@ static int command_from_LL(isdn_ctrl *cntrl) | |||
162 | } | 158 | } |
163 | *sp = cntrl->parm.setup; | 159 | *sp = cntrl->parm.setup; |
164 | 160 | ||
165 | spin_lock_irqsave(&cs->lock, flags); | 161 | if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, |
166 | param = bcs->at_state.seq_index; | 162 | bcs->at_state.seq_index, NULL)) { |
167 | spin_unlock_irqrestore(&cs->lock, flags); | ||
168 | |||
169 | if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param, | ||
170 | NULL)) { | ||
171 | //FIXME what should we do? | 163 | //FIXME what should we do? |
172 | kfree(sp); | 164 | kfree(sp); |
173 | gigaset_free_channel(bcs); | 165 | gigaset_free_channel(bcs); |
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index e767afa55abf..da6f3acf9fd0 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c | |||
@@ -19,15 +19,9 @@ | |||
19 | static ssize_t show_cidmode(struct device *dev, | 19 | static ssize_t show_cidmode(struct device *dev, |
20 | struct device_attribute *attr, char *buf) | 20 | struct device_attribute *attr, char *buf) |
21 | { | 21 | { |
22 | int ret; | ||
23 | unsigned long flags; | ||
24 | struct cardstate *cs = dev_get_drvdata(dev); | 22 | struct cardstate *cs = dev_get_drvdata(dev); |
25 | 23 | ||
26 | spin_lock_irqsave(&cs->lock, flags); | 24 | return sprintf(buf, "%u\n", cs->cidmode); |
27 | ret = sprintf(buf, "%u\n", cs->cidmode); | ||
28 | spin_unlock_irqrestore(&cs->lock, flags); | ||
29 | |||
30 | return ret; | ||
31 | } | 25 | } |
32 | 26 | ||
33 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, | 27 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, |
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index a1263019df5e..ca4bee173cfb 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c | |||
@@ -310,7 +310,6 @@ static void gigaset_modem_fill(unsigned long data) | |||
310 | struct cardstate *cs = (struct cardstate *) data; | 310 | struct cardstate *cs = (struct cardstate *) data; |
311 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ | 311 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ |
312 | struct cmdbuf_t *cb; | 312 | struct cmdbuf_t *cb; |
313 | unsigned long flags; | ||
314 | int again; | 313 | int again; |
315 | 314 | ||
316 | gig_dbg(DEBUG_OUTPUT, "modem_fill"); | 315 | gig_dbg(DEBUG_OUTPUT, "modem_fill"); |
@@ -323,9 +322,7 @@ static void gigaset_modem_fill(unsigned long data) | |||
323 | do { | 322 | do { |
324 | again = 0; | 323 | again = 0; |
325 | if (!bcs->tx_skb) { /* no skb is being sent */ | 324 | if (!bcs->tx_skb) { /* no skb is being sent */ |
326 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
327 | cb = cs->cmdbuf; | 325 | cb = cs->cmdbuf; |
328 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
329 | if (cb) { /* commands to send? */ | 326 | if (cb) { /* commands to send? */ |
330 | gig_dbg(DEBUG_OUTPUT, "modem_fill: cb"); | 327 | gig_dbg(DEBUG_OUTPUT, "modem_fill: cb"); |
331 | if (send_cb(cs, cb) < 0) { | 328 | if (send_cb(cs, cb) < 0) { |
@@ -546,13 +543,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
546 | 543 | ||
547 | static int gigaset_write_room(struct cardstate *cs) | 544 | static int gigaset_write_room(struct cardstate *cs) |
548 | { | 545 | { |
549 | unsigned long flags; | ||
550 | unsigned bytes; | 546 | unsigned bytes; |
551 | 547 | ||
552 | spin_lock_irqsave(&cs->cmdlock, flags); | ||
553 | bytes = cs->cmdbytes; | 548 | bytes = cs->cmdbytes; |
554 | spin_unlock_irqrestore(&cs->cmdlock, flags); | ||
555 | |||
556 | return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; | 549 | return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; |
557 | } | 550 | } |
558 | 551 | ||
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 4910bca52640..c6df2925ebd0 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c | |||
@@ -1365,7 +1365,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1365 | } else { | 1365 | } else { |
1366 | s = NULL; | 1366 | s = NULL; |
1367 | } | 1367 | } |
1368 | ret = down_interruptible(&dev->sem); | 1368 | ret = mutex_lock_interruptible(&dev->mtx); |
1369 | if( ret ) return ret; | 1369 | if( ret ) return ret; |
1370 | if ((s = isdn_net_new(s, NULL))) { | 1370 | if ((s = isdn_net_new(s, NULL))) { |
1371 | if (copy_to_user(argp, s, strlen(s) + 1)){ | 1371 | if (copy_to_user(argp, s, strlen(s) + 1)){ |
@@ -1375,7 +1375,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1375 | } | 1375 | } |
1376 | } else | 1376 | } else |
1377 | ret = -ENODEV; | 1377 | ret = -ENODEV; |
1378 | up(&dev->sem); | 1378 | mutex_unlock(&dev->mtx); |
1379 | return ret; | 1379 | return ret; |
1380 | case IIOCNETASL: | 1380 | case IIOCNETASL: |
1381 | /* Add a slave to a network-interface */ | 1381 | /* Add a slave to a network-interface */ |
@@ -1384,7 +1384,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1384 | return -EFAULT; | 1384 | return -EFAULT; |
1385 | } else | 1385 | } else |
1386 | return -EINVAL; | 1386 | return -EINVAL; |
1387 | ret = down_interruptible(&dev->sem); | 1387 | ret = mutex_lock_interruptible(&dev->mtx); |
1388 | if( ret ) return ret; | 1388 | if( ret ) return ret; |
1389 | if ((s = isdn_net_newslave(bname))) { | 1389 | if ((s = isdn_net_newslave(bname))) { |
1390 | if (copy_to_user(argp, s, strlen(s) + 1)){ | 1390 | if (copy_to_user(argp, s, strlen(s) + 1)){ |
@@ -1394,17 +1394,17 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1394 | } | 1394 | } |
1395 | } else | 1395 | } else |
1396 | ret = -ENODEV; | 1396 | ret = -ENODEV; |
1397 | up(&dev->sem); | 1397 | mutex_unlock(&dev->mtx); |
1398 | return ret; | 1398 | return ret; |
1399 | case IIOCNETDIF: | 1399 | case IIOCNETDIF: |
1400 | /* Delete a network-interface */ | 1400 | /* Delete a network-interface */ |
1401 | if (arg) { | 1401 | if (arg) { |
1402 | if (copy_from_user(name, argp, sizeof(name))) | 1402 | if (copy_from_user(name, argp, sizeof(name))) |
1403 | return -EFAULT; | 1403 | return -EFAULT; |
1404 | ret = down_interruptible(&dev->sem); | 1404 | ret = mutex_lock_interruptible(&dev->mtx); |
1405 | if( ret ) return ret; | 1405 | if( ret ) return ret; |
1406 | ret = isdn_net_rm(name); | 1406 | ret = isdn_net_rm(name); |
1407 | up(&dev->sem); | 1407 | mutex_unlock(&dev->mtx); |
1408 | return ret; | 1408 | return ret; |
1409 | } else | 1409 | } else |
1410 | return -EINVAL; | 1410 | return -EINVAL; |
@@ -1433,10 +1433,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1433 | if (arg) { | 1433 | if (arg) { |
1434 | if (copy_from_user(&phone, argp, sizeof(phone))) | 1434 | if (copy_from_user(&phone, argp, sizeof(phone))) |
1435 | return -EFAULT; | 1435 | return -EFAULT; |
1436 | ret = down_interruptible(&dev->sem); | 1436 | ret = mutex_lock_interruptible(&dev->mtx); |
1437 | if( ret ) return ret; | 1437 | if( ret ) return ret; |
1438 | ret = isdn_net_addphone(&phone); | 1438 | ret = isdn_net_addphone(&phone); |
1439 | up(&dev->sem); | 1439 | mutex_unlock(&dev->mtx); |
1440 | return ret; | 1440 | return ret; |
1441 | } else | 1441 | } else |
1442 | return -EINVAL; | 1442 | return -EINVAL; |
@@ -1445,10 +1445,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1445 | if (arg) { | 1445 | if (arg) { |
1446 | if (copy_from_user(&phone, argp, sizeof(phone))) | 1446 | if (copy_from_user(&phone, argp, sizeof(phone))) |
1447 | return -EFAULT; | 1447 | return -EFAULT; |
1448 | ret = down_interruptible(&dev->sem); | 1448 | ret = mutex_lock_interruptible(&dev->mtx); |
1449 | if( ret ) return ret; | 1449 | if( ret ) return ret; |
1450 | ret = isdn_net_getphones(&phone, argp); | 1450 | ret = isdn_net_getphones(&phone, argp); |
1451 | up(&dev->sem); | 1451 | mutex_unlock(&dev->mtx); |
1452 | return ret; | 1452 | return ret; |
1453 | } else | 1453 | } else |
1454 | return -EINVAL; | 1454 | return -EINVAL; |
@@ -1457,10 +1457,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) | |||
1457 | if (arg) { | 1457 | if (arg) { |
1458 | if (copy_from_user(&phone, argp, sizeof(phone))) | 1458 | if (copy_from_user(&phone, argp, sizeof(phone))) |
1459 | return -EFAULT; | 1459 | return -EFAULT; |
1460 | ret = down_interruptible(&dev->sem); | 1460 | ret = mutex_lock_interruptible(&dev->mtx); |
1461 | if( ret ) return ret; | 1461 | if( ret ) return ret; |
1462 | ret = isdn_net_delphone(&phone); | 1462 | ret = isdn_net_delphone(&phone); |
1463 | up(&dev->sem); | 1463 | mutex_unlock(&dev->mtx); |
1464 | return ret; | 1464 | return ret; |
1465 | } else | 1465 | } else |
1466 | return -EINVAL; | 1466 | return -EINVAL; |
@@ -2304,7 +2304,7 @@ static int __init isdn_init(void) | |||
2304 | #ifdef MODULE | 2304 | #ifdef MODULE |
2305 | dev->owner = THIS_MODULE; | 2305 | dev->owner = THIS_MODULE; |
2306 | #endif | 2306 | #endif |
2307 | init_MUTEX(&dev->sem); | 2307 | mutex_init(&dev->mtx); |
2308 | init_waitqueue_head(&dev->info_waitq); | 2308 | init_waitqueue_head(&dev->info_waitq); |
2309 | for (i = 0; i < ISDN_MAX_CHANNELS; i++) { | 2309 | for (i = 0; i < ISDN_MAX_CHANNELS; i++) { |
2310 | dev->drvmap[i] = -1; | 2310 | dev->drvmap[i] = -1; |
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3918ebf01e8d..626bb3c9af2b 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c | |||
@@ -2605,14 +2605,10 @@ mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd) | |||
2605 | } | 2605 | } |
2606 | 2606 | ||
2607 | /** | 2607 | /** |
2608 | * SCPNT_TO_LOOKUP_IDX | 2608 | * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list |
2609 | * | ||
2610 | * search's for a given scmd in the ScsiLookup[] array list | ||
2611 | * | ||
2612 | * @ioc: Pointer to MPT_ADAPTER structure | 2609 | * @ioc: Pointer to MPT_ADAPTER structure |
2613 | * @scmd: scsi_cmnd pointer | 2610 | * @sc: scsi_cmnd pointer |
2614 | * | 2611 | */ |
2615 | **/ | ||
2616 | static int | 2612 | static int |
2617 | SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) | 2613 | SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) |
2618 | { | 2614 | { |
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 254b194e7625..71b986b38c55 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c | |||
@@ -1280,8 +1280,8 @@ static int mmc_spi_probe(struct spi_device *spi) | |||
1280 | if (!host->data) | 1280 | if (!host->data) |
1281 | goto fail_nobuf1; | 1281 | goto fail_nobuf1; |
1282 | 1282 | ||
1283 | if (spi->master->cdev.dev->dma_mask) { | 1283 | if (spi->master->dev.parent->dma_mask) { |
1284 | struct device *dev = spi->master->cdev.dev; | 1284 | struct device *dev = spi->master->dev.parent; |
1285 | 1285 | ||
1286 | host->dma_dev = dev; | 1286 | host->dma_dev = dev; |
1287 | host->ones_dma = dma_map_single(dev, ones, | 1287 | host->ones_dma = dma_map_single(dev, ones, |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index c0c77f82d051..f201bd673137 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -2,9 +2,7 @@ | |||
2 | # PCCARD (PCMCIA/CardBus) bus subsystem configuration | 2 | # PCCARD (PCMCIA/CardBus) bus subsystem configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "PCCARD (PCMCIA/CardBus) support" | 5 | menuconfig PCCARD |
6 | |||
7 | config PCCARD | ||
8 | tristate "PCCard (PCMCIA/CardBus) support" | 6 | tristate "PCCard (PCMCIA/CardBus) support" |
9 | depends on HOTPLUG | 7 | depends on HOTPLUG |
10 | ---help--- | 8 | ---help--- |
@@ -278,5 +276,3 @@ config PCCARD_IODYN | |||
278 | bool | 276 | bool |
279 | 277 | ||
280 | endif # PCCARD | 278 | endif # PCCARD |
281 | |||
282 | endmenu | ||
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index 01874b0bb03b..ce9d5c44a7b5 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c | |||
@@ -50,7 +50,10 @@ | |||
50 | 50 | ||
51 | #include <asm/au1000.h> | 51 | #include <asm/au1000.h> |
52 | #include <asm/au1000_pcmcia.h> | 52 | #include <asm/au1000_pcmcia.h> |
53 | #include <asm/xxs1500.h> | 53 | |
54 | #define PCMCIA_MAX_SOCK 0 | ||
55 | #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1) | ||
56 | #define PCMCIA_IRQ AU1000_GPIO_4 | ||
54 | 57 | ||
55 | #if 0 | 58 | #if 0 |
56 | #define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) | 59 | #define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) |
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index d154dee76e7f..06a85d7d5aa2 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
27 | #include <asm/byteorder.h> | 27 | #include <asm/byteorder.h> |
28 | #include <asm/unaligned.h> | ||
28 | 29 | ||
29 | #include <pcmcia/cs_types.h> | 30 | #include <pcmcia/cs_types.h> |
30 | #include <pcmcia/ss.h> | 31 | #include <pcmcia/ss.h> |
@@ -401,6 +402,15 @@ EXPORT_SYMBOL(pcmcia_replace_cis); | |||
401 | 402 | ||
402 | ======================================================================*/ | 403 | ======================================================================*/ |
403 | 404 | ||
405 | static inline u16 cis_get_u16(void *ptr) | ||
406 | { | ||
407 | return le16_to_cpu(get_unaligned((__le16 *) ptr)); | ||
408 | } | ||
409 | static inline u32 cis_get_u32(void *ptr) | ||
410 | { | ||
411 | return le32_to_cpu(get_unaligned((__le32 *) ptr)); | ||
412 | } | ||
413 | |||
404 | typedef struct tuple_flags { | 414 | typedef struct tuple_flags { |
405 | u_int link_space:4; | 415 | u_int link_space:4; |
406 | u_int has_link:1; | 416 | u_int has_link:1; |
@@ -461,7 +471,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
461 | /* Get indirect link from the MFC tuple */ | 471 | /* Get indirect link from the MFC tuple */ |
462 | read_cis_cache(s, LINK_SPACE(tuple->Flags), | 472 | read_cis_cache(s, LINK_SPACE(tuple->Flags), |
463 | tuple->LinkOffset, 5, link); | 473 | tuple->LinkOffset, 5, link); |
464 | ofs = le32_to_cpu(*(__le32 *)(link+1)); | 474 | ofs = cis_get_u32(link + 1); |
465 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); | 475 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); |
466 | /* Move to the next indirect link */ | 476 | /* Move to the next indirect link */ |
467 | tuple->LinkOffset += 5; | 477 | tuple->LinkOffset += 5; |
@@ -668,10 +678,10 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) | |||
668 | u_char *p; | 678 | u_char *p; |
669 | if (tuple->TupleDataLen < 5) | 679 | if (tuple->TupleDataLen < 5) |
670 | return CS_BAD_TUPLE; | 680 | return CS_BAD_TUPLE; |
671 | p = (u_char *)tuple->TupleData; | 681 | p = (u_char *) tuple->TupleData; |
672 | csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2; | 682 | csum->addr = tuple->CISOffset + cis_get_u16(p) - 2; |
673 | csum->len = le16_to_cpu(*(__le16 *)(p + 2)); | 683 | csum->len = cis_get_u16(p + 2); |
674 | csum->sum = *(p+4); | 684 | csum->sum = *(p + 4); |
675 | return CS_SUCCESS; | 685 | return CS_SUCCESS; |
676 | } | 686 | } |
677 | 687 | ||
@@ -681,7 +691,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) | |||
681 | { | 691 | { |
682 | if (tuple->TupleDataLen < 4) | 692 | if (tuple->TupleDataLen < 4) |
683 | return CS_BAD_TUPLE; | 693 | return CS_BAD_TUPLE; |
684 | link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData); | 694 | link->addr = cis_get_u32(tuple->TupleData); |
685 | return CS_SUCCESS; | 695 | return CS_SUCCESS; |
686 | } | 696 | } |
687 | 697 | ||
@@ -700,7 +710,8 @@ static int parse_longlink_mfc(tuple_t *tuple, | |||
700 | return CS_BAD_TUPLE; | 710 | return CS_BAD_TUPLE; |
701 | for (i = 0; i < link->nfn; i++) { | 711 | for (i = 0; i < link->nfn; i++) { |
702 | link->fn[i].space = *p; p++; | 712 | link->fn[i].space = *p; p++; |
703 | link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4; | 713 | link->fn[i].addr = cis_get_u32(p); |
714 | p += 4; | ||
704 | } | 715 | } |
705 | return CS_SUCCESS; | 716 | return CS_SUCCESS; |
706 | } | 717 | } |
@@ -787,12 +798,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) | |||
787 | 798 | ||
788 | static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) | 799 | static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) |
789 | { | 800 | { |
790 | __le16 *p; | ||
791 | if (tuple->TupleDataLen < 4) | 801 | if (tuple->TupleDataLen < 4) |
792 | return CS_BAD_TUPLE; | 802 | return CS_BAD_TUPLE; |
793 | p = (__le16 *)tuple->TupleData; | 803 | m->manf = cis_get_u16(tuple->TupleData); |
794 | m->manf = le16_to_cpu(p[0]); | 804 | m->card = cis_get_u16(tuple->TupleData + 2); |
795 | m->card = le16_to_cpu(p[1]); | ||
796 | return CS_SUCCESS; | 805 | return CS_SUCCESS; |
797 | } | 806 | } |
798 | 807 | ||
@@ -1091,7 +1100,7 @@ static int parse_cftable_entry(tuple_t *tuple, | |||
1091 | break; | 1100 | break; |
1092 | case 0x20: | 1101 | case 0x20: |
1093 | entry->mem.nwin = 1; | 1102 | entry->mem.nwin = 1; |
1094 | entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; | 1103 | entry->mem.win[0].len = cis_get_u16(p) << 8; |
1095 | entry->mem.win[0].card_addr = 0; | 1104 | entry->mem.win[0].card_addr = 0; |
1096 | entry->mem.win[0].host_addr = 0; | 1105 | entry->mem.win[0].host_addr = 0; |
1097 | p += 2; | 1106 | p += 2; |
@@ -1099,9 +1108,8 @@ static int parse_cftable_entry(tuple_t *tuple, | |||
1099 | break; | 1108 | break; |
1100 | case 0x40: | 1109 | case 0x40: |
1101 | entry->mem.nwin = 1; | 1110 | entry->mem.nwin = 1; |
1102 | entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; | 1111 | entry->mem.win[0].len = cis_get_u16(p) << 8; |
1103 | entry->mem.win[0].card_addr = | 1112 | entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8; |
1104 | le16_to_cpu(*(__le16 *)(p+2)) << 8; | ||
1105 | entry->mem.win[0].host_addr = 0; | 1113 | entry->mem.win[0].host_addr = 0; |
1106 | p += 4; | 1114 | p += 4; |
1107 | if (p > q) return CS_BAD_TUPLE; | 1115 | if (p > q) return CS_BAD_TUPLE; |
@@ -1138,7 +1146,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) | |||
1138 | p = (u_char *)tuple->TupleData; | 1146 | p = (u_char *)tuple->TupleData; |
1139 | bar->attr = *p; | 1147 | bar->attr = *p; |
1140 | p += 2; | 1148 | p += 2; |
1141 | bar->size = le32_to_cpu(*(__le32 *)p); | 1149 | bar->size = cis_get_u32(p); |
1142 | return CS_SUCCESS; | 1150 | return CS_SUCCESS; |
1143 | } | 1151 | } |
1144 | 1152 | ||
@@ -1151,7 +1159,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) | |||
1151 | return CS_BAD_TUPLE; | 1159 | return CS_BAD_TUPLE; |
1152 | config->last_idx = *(++p); | 1160 | config->last_idx = *(++p); |
1153 | p++; | 1161 | p++; |
1154 | config->base = le32_to_cpu(*(__le32 *)p); | 1162 | config->base = cis_get_u32(p); |
1155 | config->subtuples = tuple->TupleDataLen - 6; | 1163 | config->subtuples = tuple->TupleDataLen - 6; |
1156 | return CS_SUCCESS; | 1164 | return CS_SUCCESS; |
1157 | } | 1165 | } |
@@ -1267,7 +1275,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) | |||
1267 | 1275 | ||
1268 | v2->vers = p[0]; | 1276 | v2->vers = p[0]; |
1269 | v2->comply = p[1]; | 1277 | v2->comply = p[1]; |
1270 | v2->dindex = le16_to_cpu(*(__le16 *)(p+2)); | 1278 | v2->dindex = cis_get_u16(p +2 ); |
1271 | v2->vspec8 = p[6]; | 1279 | v2->vspec8 = p[6]; |
1272 | v2->vspec9 = p[7]; | 1280 | v2->vspec9 = p[7]; |
1273 | v2->nhdr = p[8]; | 1281 | v2->nhdr = p[8]; |
@@ -1308,8 +1316,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) | |||
1308 | 1316 | ||
1309 | fmt->type = p[0]; | 1317 | fmt->type = p[0]; |
1310 | fmt->edc = p[1]; | 1318 | fmt->edc = p[1]; |
1311 | fmt->offset = le32_to_cpu(*(__le32 *)(p+2)); | 1319 | fmt->offset = cis_get_u32(p + 2); |
1312 | fmt->length = le32_to_cpu(*(__le32 *)(p+6)); | 1320 | fmt->length = cis_get_u32(p + 6); |
1313 | 1321 | ||
1314 | return CS_SUCCESS; | 1322 | return CS_SUCCESS; |
1315 | } | 1323 | } |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 55baa1f0fcbb..7bf78c127898 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/crc32.h> | 23 | #include <linux/crc32.h> |
24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/kref.h> | 25 | #include <linux/kref.h> |
26 | #include <linux/dma-mapping.h> | ||
26 | 27 | ||
27 | #define IN_CARD_SERVICES | 28 | #define IN_CARD_SERVICES |
28 | #include <pcmcia/cs_types.h> | 29 | #include <pcmcia/cs_types.h> |
@@ -670,6 +671,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
670 | p_dev->dev.bus = &pcmcia_bus_type; | 671 | p_dev->dev.bus = &pcmcia_bus_type; |
671 | p_dev->dev.parent = s->dev.parent; | 672 | p_dev->dev.parent = s->dev.parent; |
672 | p_dev->dev.release = pcmcia_release_dev; | 673 | p_dev->dev.release = pcmcia_release_dev; |
674 | /* by default don't allow DMA */ | ||
675 | p_dev->dma_mask = DMA_MASK_NONE; | ||
676 | p_dev->dev.dma_mask = &p_dev->dma_mask; | ||
673 | bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); | 677 | bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); |
674 | 678 | ||
675 | p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); | 679 | p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); |
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index dca9f8549b32..874923fcb2f9 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c | |||
@@ -58,7 +58,7 @@ static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns, | |||
58 | u_int mem_clk_10khz) | 58 | u_int mem_clk_10khz) |
59 | { | 59 | { |
60 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; | 60 | u_int code = pcmcia_cycle_ns * mem_clk_10khz; |
61 | return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; | 61 | return (code / 300000) + ((code % 300000) ? 1 : 0) + 1; |
62 | } | 62 | } |
63 | 63 | ||
64 | static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, | 64 | static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, |
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 85e21614f868..397f4ce849dc 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/notifier.h> | 24 | #include <linux/notifier.h> |
25 | #include <linux/ioctl.h> | 25 | #include <linux/ioctl.h> |
26 | #include <linux/fb.h> | ||
26 | 27 | ||
27 | #include <asm/firmware.h> | 28 | #include <asm/firmware.h> |
28 | #include <asm/ps3av.h> | 29 | #include <asm/ps3av.h> |
@@ -33,6 +34,8 @@ | |||
33 | #define BUFSIZE 4096 /* vuart buf size */ | 34 | #define BUFSIZE 4096 /* vuart buf size */ |
34 | #define PS3AV_BUF_SIZE 512 /* max packet size */ | 35 | #define PS3AV_BUF_SIZE 512 /* max packet size */ |
35 | 36 | ||
37 | static int safe_mode; | ||
38 | |||
36 | static int timeout = 5000; /* in msec ( 5 sec ) */ | 39 | static int timeout = 5000; /* in msec ( 5 sec ) */ |
37 | module_param(timeout, int, 0644); | 40 | module_param(timeout, int, 0644); |
38 | 41 | ||
@@ -491,10 +494,10 @@ static int ps3av_set_videomode(void) | |||
491 | return 0; | 494 | return 0; |
492 | } | 495 | } |
493 | 496 | ||
494 | static void ps3av_set_videomode_cont(u32 id, u32 old_id) | 497 | static void ps3av_set_videomode_packet(u32 id) |
495 | { | 498 | { |
496 | struct ps3av_pkt_avb_param avb_param; | 499 | struct ps3av_pkt_avb_param avb_param; |
497 | int i; | 500 | unsigned int i; |
498 | u32 len = 0, av_video_cs; | 501 | u32 len = 0, av_video_cs; |
499 | const struct avset_video_mode *video_mode; | 502 | const struct avset_video_mode *video_mode; |
500 | int res; | 503 | int res; |
@@ -507,24 +510,6 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
507 | ps3av->av_hw_conf.num_of_avmulti; | 510 | ps3av->av_hw_conf.num_of_avmulti; |
508 | avb_param.num_of_av_audio_pkt = 0; | 511 | avb_param.num_of_av_audio_pkt = 0; |
509 | 512 | ||
510 | /* video signal off */ | ||
511 | ps3av_set_video_disable_sig(); | ||
512 | |||
513 | /* Retail PS3 product doesn't support this */ | ||
514 | if (id & PS3AV_MODE_HDCP_OFF) { | ||
515 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); | ||
516 | if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | ||
517 | dev_dbg(&ps3av->dev->core, "Not supported\n"); | ||
518 | else if (res) | ||
519 | dev_dbg(&ps3av->dev->core, | ||
520 | "ps3av_cmd_av_hdmi_mode failed\n"); | ||
521 | } else if (old_id & PS3AV_MODE_HDCP_OFF) { | ||
522 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); | ||
523 | if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | ||
524 | dev_dbg(&ps3av->dev->core, | ||
525 | "ps3av_cmd_av_hdmi_mode failed\n"); | ||
526 | } | ||
527 | |||
528 | /* video_pkt */ | 513 | /* video_pkt */ |
529 | for (i = 0; i < avb_param.num_of_video_pkt; i++) | 514 | for (i = 0; i < avb_param.num_of_video_pkt; i++) |
530 | len += ps3av_cmd_set_video_mode(&avb_param.buf[len], | 515 | len += ps3av_cmd_set_video_mode(&avb_param.buf[len], |
@@ -555,6 +540,42 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
555 | __func__); | 540 | __func__); |
556 | else if (res) | 541 | else if (res) |
557 | dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); | 542 | dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); |
543 | } | ||
544 | |||
545 | static void ps3av_set_videomode_cont(u32 id, u32 old_id) | ||
546 | { | ||
547 | static int vesa = 0; | ||
548 | int res; | ||
549 | |||
550 | /* video signal off */ | ||
551 | ps3av_set_video_disable_sig(); | ||
552 | |||
553 | /* | ||
554 | * AV backend needs non-VESA mode setting at least one time | ||
555 | * when VESA mode is used. | ||
556 | */ | ||
557 | if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) { | ||
558 | /* vesa mode */ | ||
559 | ps3av_set_videomode_packet(2); /* 480P */ | ||
560 | } | ||
561 | vesa = 1; | ||
562 | |||
563 | /* Retail PS3 product doesn't support this */ | ||
564 | if (id & PS3AV_MODE_HDCP_OFF) { | ||
565 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); | ||
566 | if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | ||
567 | dev_dbg(&ps3av->dev->core, "Not supported\n"); | ||
568 | else if (res) | ||
569 | dev_dbg(&ps3av->dev->core, | ||
570 | "ps3av_cmd_av_hdmi_mode failed\n"); | ||
571 | } else if (old_id & PS3AV_MODE_HDCP_OFF) { | ||
572 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); | ||
573 | if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | ||
574 | dev_dbg(&ps3av->dev->core, | ||
575 | "ps3av_cmd_av_hdmi_mode failed\n"); | ||
576 | } | ||
577 | |||
578 | ps3av_set_videomode_packet(id); | ||
558 | 579 | ||
559 | msleep(1500); | 580 | msleep(1500); |
560 | /* av video mute */ | 581 | /* av video mute */ |
@@ -567,165 +588,251 @@ static void ps3avd(struct work_struct *work) | |||
567 | complete(&ps3av->done); | 588 | complete(&ps3av->done); |
568 | } | 589 | } |
569 | 590 | ||
570 | static int ps3av_vid2table_id(int vid) | 591 | #define SHIFT_50 0 |
571 | { | 592 | #define SHIFT_60 4 |
572 | int i; | 593 | #define SHIFT_VESA 8 |
573 | 594 | ||
574 | for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) | 595 | static const struct { |
575 | if (video_mode_table[i].vid == vid) | 596 | unsigned mask : 19; |
576 | return i; | 597 | unsigned id : 4; |
577 | return -1; | 598 | } ps3av_preferred_modes[] = { |
578 | } | 599 | { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 }, |
600 | { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 }, | ||
601 | { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 }, | ||
602 | { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 }, | ||
603 | { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 }, | ||
604 | { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 }, | ||
605 | { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 }, | ||
606 | { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 }, | ||
607 | { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 }, | ||
608 | { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 }, | ||
609 | { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 }, | ||
610 | }; | ||
579 | 611 | ||
580 | static int ps3av_resbit2vid(u32 res_50, u32 res_60) | 612 | static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa) |
581 | { | 613 | { |
582 | int vid = -1; | 614 | unsigned int i; |
615 | u32 res_all; | ||
616 | |||
617 | /* | ||
618 | * We mask off the resolution bits we care about and combine the | ||
619 | * results in one bitfield, so make sure there's no overlap | ||
620 | */ | ||
621 | BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & | ||
622 | PS3AV_RES_MASK_60 << SHIFT_60); | ||
623 | BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & | ||
624 | PS3AV_RES_MASK_VESA << SHIFT_VESA); | ||
625 | BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 & | ||
626 | PS3AV_RES_MASK_VESA << SHIFT_VESA); | ||
627 | res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 | | ||
628 | (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 | | ||
629 | (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA; | ||
630 | |||
631 | if (!res_all) | ||
632 | return 0; | ||
633 | |||
634 | for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++) | ||
635 | if (res_all & ps3av_preferred_modes[i].mask) | ||
636 | return ps3av_preferred_modes[i].id; | ||
583 | 637 | ||
584 | if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ | 638 | return 0; |
585 | if (res_50 & PS3AV_RESBIT_1920x1080P) | ||
586 | vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; | ||
587 | else if (res_50 & PS3AV_RESBIT_1920x1080I) | ||
588 | vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; | ||
589 | else if (res_50 & PS3AV_RESBIT_1280x720P) | ||
590 | vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; | ||
591 | else if (res_50 & PS3AV_RESBIT_720x576P) | ||
592 | vid = PS3AV_CMD_VIDEO_VID_576P; | ||
593 | else | ||
594 | vid = -1; | ||
595 | } else { | ||
596 | if (res_60 & PS3AV_RESBIT_1920x1080P) | ||
597 | vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; | ||
598 | else if (res_60 & PS3AV_RESBIT_1920x1080I) | ||
599 | vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; | ||
600 | else if (res_60 & PS3AV_RESBIT_1280x720P) | ||
601 | vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; | ||
602 | else if (res_60 & PS3AV_RESBIT_720x480P) | ||
603 | vid = PS3AV_CMD_VIDEO_VID_480P; | ||
604 | else | ||
605 | vid = -1; | ||
606 | } | ||
607 | return vid; | ||
608 | } | 639 | } |
609 | 640 | ||
610 | static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) | 641 | static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info) |
611 | { | 642 | { |
612 | u32 res_50, res_60; | 643 | int id; |
613 | int vid = -1; | ||
614 | 644 | ||
615 | if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) | 645 | if (safe_mode) |
616 | return -1; | 646 | return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; |
617 | 647 | ||
618 | /* check native resolution */ | 648 | /* check native resolution */ |
619 | res_50 = info->res_50.native & PS3AV_RES_MASK_50; | 649 | id = ps3av_resbit2id(info->res_50.native, info->res_60.native, |
620 | res_60 = info->res_60.native & PS3AV_RES_MASK_60; | 650 | info->res_vesa.native); |
621 | if (res_50 || res_60) { | 651 | if (id) { |
622 | vid = ps3av_resbit2vid(res_50, res_60); | 652 | pr_debug("%s: Using native mode %d\n", __func__, id); |
623 | return vid; | 653 | return id; |
624 | } | 654 | } |
625 | 655 | ||
626 | /* check resolution */ | 656 | /* check supported resolutions */ |
627 | res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; | 657 | id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits, |
628 | res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; | 658 | info->res_vesa.res_bits); |
629 | if (res_50 || res_60) { | 659 | if (id) { |
630 | vid = ps3av_resbit2vid(res_50, res_60); | 660 | pr_debug("%s: Using supported mode %d\n", __func__, id); |
631 | return vid; | 661 | return id; |
632 | } | 662 | } |
633 | 663 | ||
634 | if (ps3av->region & PS3AV_REGION_60) | 664 | if (ps3av->region & PS3AV_REGION_60) |
635 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | 665 | id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; |
636 | else | 666 | else |
637 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; | 667 | id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50; |
638 | return vid; | 668 | pr_debug("%s: Using default mode %d\n", __func__, id); |
669 | return id; | ||
639 | } | 670 | } |
640 | 671 | ||
641 | static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, | 672 | static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) |
642 | int boot) | ||
643 | { | 673 | { |
644 | int i, res, vid = -1, dvi = 0, rgb = 0; | 674 | const struct ps3av_info_monitor *info = &monitor_info->info; |
675 | const struct ps3av_info_audio *audio = info->audio; | ||
676 | char id[sizeof(info->monitor_id)*3+1]; | ||
677 | int i; | ||
678 | |||
679 | pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size); | ||
680 | |||
681 | pr_debug("avport: %02x\n", info->avport); | ||
682 | for (i = 0; i < sizeof(info->monitor_id); i++) | ||
683 | sprintf(&id[i*3], " %02x", info->monitor_id[i]); | ||
684 | pr_debug("monitor_id: %s\n", id); | ||
685 | pr_debug("monitor_type: %02x\n", info->monitor_type); | ||
686 | pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name), | ||
687 | info->monitor_name); | ||
688 | |||
689 | /* resolution */ | ||
690 | pr_debug("resolution_60: bits: %08x native: %08x\n", | ||
691 | info->res_60.res_bits, info->res_60.native); | ||
692 | pr_debug("resolution_50: bits: %08x native: %08x\n", | ||
693 | info->res_50.res_bits, info->res_50.native); | ||
694 | pr_debug("resolution_other: bits: %08x native: %08x\n", | ||
695 | info->res_other.res_bits, info->res_other.native); | ||
696 | pr_debug("resolution_vesa: bits: %08x native: %08x\n", | ||
697 | info->res_vesa.res_bits, info->res_vesa.native); | ||
698 | |||
699 | /* color space */ | ||
700 | pr_debug("color space rgb: %02x\n", info->cs.rgb); | ||
701 | pr_debug("color space yuv444: %02x\n", info->cs.yuv444); | ||
702 | pr_debug("color space yuv422: %02x\n", info->cs.yuv422); | ||
703 | |||
704 | /* color info */ | ||
705 | pr_debug("color info red: X %04x Y %04x\n", info->color.red_x, | ||
706 | info->color.red_y); | ||
707 | pr_debug("color info green: X %04x Y %04x\n", info->color.green_x, | ||
708 | info->color.green_y); | ||
709 | pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x, | ||
710 | info->color.blue_y); | ||
711 | pr_debug("color info white: X %04x Y %04x\n", info->color.white_x, | ||
712 | info->color.white_y); | ||
713 | pr_debug("color info gamma: %08x\n", info->color.gamma); | ||
714 | |||
715 | /* other info */ | ||
716 | pr_debug("supported_AI: %02x\n", info->supported_ai); | ||
717 | pr_debug("speaker_info: %02x\n", info->speaker_info); | ||
718 | pr_debug("num of audio: %02x\n", info->num_of_audio_block); | ||
719 | |||
720 | /* audio block */ | ||
721 | for (i = 0; i < info->num_of_audio_block; i++) { | ||
722 | pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: " | ||
723 | "%02x\n", | ||
724 | i, audio->type, audio->max_num_of_ch, audio->fs, | ||
725 | audio->sbit); | ||
726 | audio++; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | static const struct ps3av_monitor_quirk { | ||
731 | const char *monitor_name; | ||
732 | u32 clear_60, clear_50, clear_vesa; | ||
733 | } ps3av_monitor_quirks[] = { | ||
734 | { | ||
735 | .monitor_name = "DELL 2007WFP", | ||
736 | .clear_60 = PS3AV_RESBIT_1920x1080I | ||
737 | }, { | ||
738 | .monitor_name = "L226WTQ", | ||
739 | .clear_60 = PS3AV_RESBIT_1920x1080I | | ||
740 | PS3AV_RESBIT_1920x1080P | ||
741 | }, { | ||
742 | .monitor_name = "SyncMaster", | ||
743 | .clear_60 = PS3AV_RESBIT_1920x1080I | ||
744 | } | ||
745 | }; | ||
746 | |||
747 | static void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info) | ||
748 | { | ||
749 | unsigned int i; | ||
750 | const struct ps3av_monitor_quirk *quirk; | ||
751 | |||
752 | for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) { | ||
753 | quirk = &ps3av_monitor_quirks[i]; | ||
754 | if (!strncmp(info->monitor_name, quirk->monitor_name, | ||
755 | sizeof(info->monitor_name))) { | ||
756 | pr_info("%s: Applying quirk for %s\n", __func__, | ||
757 | quirk->monitor_name); | ||
758 | info->res_60.res_bits &= ~quirk->clear_60; | ||
759 | info->res_60.native &= ~quirk->clear_60; | ||
760 | info->res_50.res_bits &= ~quirk->clear_50; | ||
761 | info->res_50.native &= ~quirk->clear_50; | ||
762 | info->res_vesa.res_bits &= ~quirk->clear_vesa; | ||
763 | info->res_vesa.native &= ~quirk->clear_vesa; | ||
764 | break; | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | |||
769 | static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf) | ||
770 | { | ||
771 | int i, res, id = 0, dvi = 0, rgb = 0; | ||
645 | struct ps3av_pkt_av_get_monitor_info monitor_info; | 772 | struct ps3av_pkt_av_get_monitor_info monitor_info; |
646 | struct ps3av_info_monitor *info; | 773 | struct ps3av_info_monitor *info; |
647 | 774 | ||
648 | /* get vid for hdmi */ | 775 | /* get mode id for hdmi */ |
649 | for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { | 776 | for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) { |
650 | res = ps3av_cmd_video_get_monitor_info(&monitor_info, | 777 | res = ps3av_cmd_video_get_monitor_info(&monitor_info, |
651 | PS3AV_CMD_AVPORT_HDMI_0 + | 778 | PS3AV_CMD_AVPORT_HDMI_0 + |
652 | i); | 779 | i); |
653 | if (res < 0) | 780 | if (res < 0) |
654 | return -1; | 781 | return -1; |
655 | 782 | ||
656 | ps3av_cmd_av_monitor_info_dump(&monitor_info); | 783 | ps3av_monitor_info_dump(&monitor_info); |
784 | |||
657 | info = &monitor_info.info; | 785 | info = &monitor_info.info; |
658 | /* check DVI */ | 786 | ps3av_fixup_monitor_info(info); |
659 | if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { | 787 | |
788 | switch (info->monitor_type) { | ||
789 | case PS3AV_MONITOR_TYPE_DVI: | ||
660 | dvi = PS3AV_MODE_DVI; | 790 | dvi = PS3AV_MODE_DVI; |
661 | break; | 791 | /* fall through */ |
662 | } | 792 | case PS3AV_MONITOR_TYPE_HDMI: |
663 | /* check HDMI */ | 793 | id = ps3av_hdmi_get_id(info); |
664 | vid = ps3av_hdmi_get_vid(info); | ||
665 | if (vid != -1) { | ||
666 | /* got valid vid */ | ||
667 | break; | 794 | break; |
668 | } | 795 | } |
669 | } | 796 | } |
670 | 797 | ||
671 | if (dvi) { | 798 | if (!id) { |
672 | /* DVI mode */ | ||
673 | vid = PS3AV_DEFAULT_DVI_VID; | ||
674 | } else if (vid == -1) { | ||
675 | /* no HDMI interface or HDMI is off */ | 799 | /* no HDMI interface or HDMI is off */ |
676 | if (ps3av->region & PS3AV_REGION_60) | 800 | if (ps3av->region & PS3AV_REGION_60) |
677 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; | 801 | id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60; |
678 | else | 802 | else |
679 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; | 803 | id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50; |
680 | if (ps3av->region & PS3AV_REGION_RGB) | 804 | if (ps3av->region & PS3AV_REGION_RGB) |
681 | rgb = PS3AV_MODE_RGB; | 805 | rgb = PS3AV_MODE_RGB; |
682 | } else if (boot) { | 806 | pr_debug("%s: Using avmulti mode %d\n", __func__, id); |
683 | /* HDMI: using DEFAULT HDMI_VID while booting up */ | ||
684 | info = &monitor_info.info; | ||
685 | if (ps3av->region & PS3AV_REGION_60) { | ||
686 | if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) | ||
687 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | ||
688 | else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) | ||
689 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; | ||
690 | else { | ||
691 | /* default */ | ||
692 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | ||
693 | } | ||
694 | } else { | ||
695 | if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) | ||
696 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; | ||
697 | else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) | ||
698 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | ||
699 | else { | ||
700 | /* default */ | ||
701 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; | ||
702 | } | ||
703 | } | ||
704 | } | 807 | } |
705 | 808 | ||
706 | return (ps3av_vid2table_id(vid) | dvi | rgb); | 809 | return id | dvi | rgb; |
707 | } | 810 | } |
708 | 811 | ||
709 | static int ps3av_get_hw_conf(struct ps3av *ps3av) | 812 | static int ps3av_get_hw_conf(struct ps3av *ps3av) |
710 | { | 813 | { |
711 | int i, j, k, res; | 814 | int i, j, k, res; |
815 | const struct ps3av_pkt_av_get_hw_conf *hw_conf; | ||
712 | 816 | ||
713 | /* get av_hw_conf */ | 817 | /* get av_hw_conf */ |
714 | res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); | 818 | res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); |
715 | if (res < 0) | 819 | if (res < 0) |
716 | return -1; | 820 | return -1; |
717 | 821 | ||
718 | ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf); | 822 | hw_conf = &ps3av->av_hw_conf; |
823 | pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi); | ||
824 | pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti); | ||
825 | pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif); | ||
719 | 826 | ||
720 | for (i = 0; i < PS3AV_HEAD_MAX; i++) | 827 | for (i = 0; i < PS3AV_HEAD_MAX; i++) |
721 | ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; | 828 | ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; |
722 | for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) | 829 | for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) |
723 | ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; | 830 | ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; |
724 | for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++) | 831 | for (i = 0; i < hw_conf->num_of_hdmi; i++) |
725 | ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; | 832 | ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; |
726 | for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++) | 833 | for (j = 0; j < hw_conf->num_of_avmulti; j++) |
727 | ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; | 834 | ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; |
728 | for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++) | 835 | for (k = 0; k < hw_conf->num_of_spdif; k++) |
729 | ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; | 836 | ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; |
730 | 837 | ||
731 | /* set all audio port */ | 838 | /* set all audio port */ |
@@ -738,7 +845,7 @@ static int ps3av_get_hw_conf(struct ps3av *ps3av) | |||
738 | } | 845 | } |
739 | 846 | ||
740 | /* set mode using id */ | 847 | /* set mode using id */ |
741 | int ps3av_set_video_mode(u32 id, int boot) | 848 | int ps3av_set_video_mode(u32 id) |
742 | { | 849 | { |
743 | int size; | 850 | int size; |
744 | u32 option; | 851 | u32 option; |
@@ -752,7 +859,7 @@ int ps3av_set_video_mode(u32 id, int boot) | |||
752 | /* auto mode */ | 859 | /* auto mode */ |
753 | option = id & ~PS3AV_MODE_MASK; | 860 | option = id & ~PS3AV_MODE_MASK; |
754 | if ((id & PS3AV_MODE_MASK) == 0) { | 861 | if ((id & PS3AV_MODE_MASK) == 0) { |
755 | id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot); | 862 | id = ps3av_auto_videomode(&ps3av->av_hw_conf); |
756 | if (id < 1) { | 863 | if (id < 1) { |
757 | printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); | 864 | printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); |
758 | return -EINVAL; | 865 | return -EINVAL; |
@@ -772,34 +879,13 @@ int ps3av_set_video_mode(u32 id, int boot) | |||
772 | 879 | ||
773 | EXPORT_SYMBOL_GPL(ps3av_set_video_mode); | 880 | EXPORT_SYMBOL_GPL(ps3av_set_video_mode); |
774 | 881 | ||
775 | int ps3av_get_auto_mode(int boot) | 882 | int ps3av_get_auto_mode(void) |
776 | { | 883 | { |
777 | return ps3av_auto_videomode(&ps3av->av_hw_conf, boot); | 884 | return ps3av_auto_videomode(&ps3av->av_hw_conf); |
778 | } | 885 | } |
779 | 886 | ||
780 | EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); | 887 | EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); |
781 | 888 | ||
782 | int ps3av_set_mode(u32 id, int boot) | ||
783 | { | ||
784 | int res; | ||
785 | |||
786 | res = ps3av_set_video_mode(id, boot); | ||
787 | if (res) | ||
788 | return res; | ||
789 | |||
790 | res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, | ||
791 | PS3AV_CMD_AUDIO_FS_48K, | ||
792 | PS3AV_CMD_AUDIO_WORD_BITS_16, | ||
793 | PS3AV_CMD_AUDIO_FORMAT_PCM, | ||
794 | PS3AV_CMD_AUDIO_SOURCE_SERIAL); | ||
795 | if (res) | ||
796 | return res; | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | EXPORT_SYMBOL_GPL(ps3av_set_mode); | ||
802 | |||
803 | int ps3av_get_mode(void) | 889 | int ps3av_get_mode(void) |
804 | { | 890 | { |
805 | return ps3av ? ps3av->ps3av_mode : 0; | 891 | return ps3av ? ps3av->ps3av_mode : 0; |
@@ -941,7 +1027,14 @@ static int ps3av_probe(struct ps3_system_bus_device *dev) | |||
941 | res); | 1027 | res); |
942 | 1028 | ||
943 | ps3av_get_hw_conf(ps3av); | 1029 | ps3av_get_hw_conf(ps3av); |
944 | id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1); | 1030 | |
1031 | #ifdef CONFIG_FB | ||
1032 | if (fb_mode_option && !strcmp(fb_mode_option, "safe")) | ||
1033 | safe_mode = 1; | ||
1034 | #endif /* CONFIG_FB */ | ||
1035 | id = ps3av_auto_videomode(&ps3av->av_hw_conf); | ||
1036 | safe_mode = 0; | ||
1037 | |||
945 | mutex_lock(&ps3av->mutex); | 1038 | mutex_lock(&ps3av->mutex); |
946 | ps3av->ps3av_mode = id; | 1039 | ps3av->ps3av_mode = id; |
947 | mutex_unlock(&ps3av->mutex); | 1040 | mutex_unlock(&ps3av->mutex); |
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index f72f5ddf18e4..7f880c26122f 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c | |||
@@ -512,7 +512,6 @@ static const u32 ps3av_ns_table[][5] = { | |||
512 | static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) | 512 | static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) |
513 | { | 513 | { |
514 | u32 av_vid, ns_val; | 514 | u32 av_vid, ns_val; |
515 | u8 *p = ns; | ||
516 | int d; | 515 | int d; |
517 | 516 | ||
518 | d = ns_val = 0; | 517 | d = ns_val = 0; |
@@ -551,24 +550,22 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) | |||
551 | else | 550 | else |
552 | ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; | 551 | ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; |
553 | 552 | ||
554 | *p++ = ns_val & 0x000000FF; | 553 | *ns++ = ns_val & 0x000000FF; |
555 | *p++ = (ns_val & 0x0000FF00) >> 8; | 554 | *ns++ = (ns_val & 0x0000FF00) >> 8; |
556 | *p = (ns_val & 0x00FF0000) >> 16; | 555 | *ns = (ns_val & 0x00FF0000) >> 16; |
557 | } | 556 | } |
558 | 557 | ||
559 | #undef BASE | 558 | #undef BASE |
560 | 559 | ||
561 | static u8 ps3av_cnv_enable(u32 source, const u8 *enable) | 560 | static u8 ps3av_cnv_enable(u32 source, const u8 *enable) |
562 | { | 561 | { |
563 | const u8 *p; | ||
564 | u8 ret = 0; | 562 | u8 ret = 0; |
565 | 563 | ||
566 | if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) { | 564 | if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) { |
567 | ret = 0x03; | 565 | ret = 0x03; |
568 | } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) { | 566 | } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) { |
569 | p = enable; | 567 | ret = ((enable[0] << 4) + (enable[1] << 5) + (enable[2] << 6) + |
570 | ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) | | 568 | (enable[3] << 7)) | 0x01; |
571 | 0x01; | ||
572 | } else | 569 | } else |
573 | printk(KERN_ERR "%s failed, source:%x\n", __func__, source); | 570 | printk(KERN_ERR "%s failed, source:%x\n", __func__, source); |
574 | return ret; | 571 | return ret; |
@@ -576,11 +573,9 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable) | |||
576 | 573 | ||
577 | static u8 ps3av_cnv_fifomap(const u8 *map) | 574 | static u8 ps3av_cnv_fifomap(const u8 *map) |
578 | { | 575 | { |
579 | const u8 *p; | ||
580 | u8 ret = 0; | 576 | u8 ret = 0; |
581 | 577 | ||
582 | p = map; | 578 | ret = map[0] + (map[1] << 2) + (map[2] << 4) + (map[3] << 6); |
583 | ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6); | ||
584 | return ret; | 579 | return ret; |
585 | } | 580 | } |
586 | 581 | ||
@@ -927,72 +922,6 @@ int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info, | |||
927 | return res; | 922 | return res; |
928 | } | 923 | } |
929 | 924 | ||
930 | #ifdef PS3AV_DEBUG | ||
931 | void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf) | ||
932 | { | ||
933 | printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi); | ||
934 | printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti); | ||
935 | printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif); | ||
936 | } | ||
937 | |||
938 | void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) | ||
939 | { | ||
940 | const struct ps3av_info_monitor *info = &monitor_info->info; | ||
941 | const struct ps3av_info_audio *audio = info->audio; | ||
942 | int i; | ||
943 | |||
944 | printk("Monitor Info: size%d\n", monitor_info->send_hdr.size); | ||
945 | |||
946 | printk("avport:%02x\n", info->avport); | ||
947 | printk("monitor_id:"); | ||
948 | for (i = 0; i < 10; i++) | ||
949 | printk("%02x ", info->monitor_id[i]); | ||
950 | printk("\nmonitor_type:%02x\n", info->monitor_type); | ||
951 | printk("monitor_name:"); | ||
952 | for (i = 0; i < 16; i++) | ||
953 | printk("%c", info->monitor_name[i]); | ||
954 | |||
955 | /* resolution */ | ||
956 | printk("\nresolution_60: bits:%08x native:%08x\n", | ||
957 | info->res_60.res_bits, info->res_60.native); | ||
958 | printk("resolution_50: bits:%08x native:%08x\n", | ||
959 | info->res_50.res_bits, info->res_50.native); | ||
960 | printk("resolution_other: bits:%08x native:%08x\n", | ||
961 | info->res_other.res_bits, info->res_other.native); | ||
962 | printk("resolution_vesa: bits:%08x native:%08x\n", | ||
963 | info->res_vesa.res_bits, info->res_vesa.native); | ||
964 | |||
965 | /* color space */ | ||
966 | printk("color space rgb:%02x\n", info->cs.rgb); | ||
967 | printk("color space yuv444:%02x\n", info->cs.yuv444); | ||
968 | printk("color space yuv422:%02x\n", info->cs.yuv422); | ||
969 | |||
970 | /* color info */ | ||
971 | printk("color info red:X %04x Y %04x\n", | ||
972 | info->color.red_x, info->color.red_y); | ||
973 | printk("color info green:X %04x Y %04x\n", | ||
974 | info->color.green_x, info->color.green_y); | ||
975 | printk("color info blue:X %04x Y %04x\n", | ||
976 | info->color.blue_x, info->color.blue_y); | ||
977 | printk("color info white:X %04x Y %04x\n", | ||
978 | info->color.white_x, info->color.white_y); | ||
979 | printk("color info gamma: %08x\n", info->color.gamma); | ||
980 | |||
981 | /* other info */ | ||
982 | printk("supported_AI:%02x\n", info->supported_ai); | ||
983 | printk("speaker_info:%02x\n", info->speaker_info); | ||
984 | printk("num of audio:%02x\n", info->num_of_audio_block); | ||
985 | |||
986 | /* audio block */ | ||
987 | for (i = 0; i < info->num_of_audio_block; i++) { | ||
988 | printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n", | ||
989 | i, audio->type, audio->max_num_of_ch, audio->fs, | ||
990 | audio->sbit); | ||
991 | audio++; | ||
992 | } | ||
993 | } | ||
994 | #endif /* PS3AV_DEBUG */ | ||
995 | |||
996 | #define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \ | 925 | #define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \ |
997 | | PS3AV_CMD_AV_LAYOUT_44 \ | 926 | | PS3AV_CMD_AV_LAYOUT_44 \ |
998 | | PS3AV_CMD_AV_LAYOUT_48) | 927 | | PS3AV_CMD_AV_LAYOUT_48) |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ff9e35cb308d..6420a90a4a92 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -139,6 +139,17 @@ config RTC_DRV_DS1307 | |||
139 | This driver can also be built as a module. If so, the module | 139 | This driver can also be built as a module. If so, the module |
140 | will be called rtc-ds1307. | 140 | will be called rtc-ds1307. |
141 | 141 | ||
142 | config RTC_DRV_DS1374 | ||
143 | tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" | ||
144 | depends on RTC_CLASS && I2C | ||
145 | help | ||
146 | If you say yes here you get support for Dallas Semiconductor | ||
147 | DS1374 real-time clock chips. If an interrupt is associated | ||
148 | with the device, the alarm functionality is supported. | ||
149 | |||
150 | This driver can also be built as a module. If so, the module | ||
151 | will be called rtc-ds1374. | ||
152 | |||
142 | config RTC_DRV_DS1672 | 153 | config RTC_DRV_DS1672 |
143 | tristate "Dallas/Maxim DS1672" | 154 | tristate "Dallas/Maxim DS1672" |
144 | help | 155 | help |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3a33aa2696f..465db4dd50b2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o | |||
23 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o | 23 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o |
24 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o | 24 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o |
25 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o | 25 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o |
26 | obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o | ||
26 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | 27 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o |
27 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 28 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
28 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | 29 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o |
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 10ab3b71ffc6..4dfdf019fccc 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -153,6 +153,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
153 | mutex_init(&rtc->ops_lock); | 153 | mutex_init(&rtc->ops_lock); |
154 | spin_lock_init(&rtc->irq_lock); | 154 | spin_lock_init(&rtc->irq_lock); |
155 | spin_lock_init(&rtc->irq_task_lock); | 155 | spin_lock_init(&rtc->irq_task_lock); |
156 | init_waitqueue_head(&rtc->irq_queue); | ||
156 | 157 | ||
157 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); | 158 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); |
158 | snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); | 159 | snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); |
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index ad66c6ecf365..de0da545c7a1 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -12,6 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/rtc.h> | 14 | #include <linux/rtc.h> |
15 | #include <linux/log2.h> | ||
15 | 16 | ||
16 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | 17 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) |
17 | { | 18 | { |
@@ -99,7 +100,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
99 | } | 100 | } |
100 | EXPORT_SYMBOL_GPL(rtc_set_mmss); | 101 | EXPORT_SYMBOL_GPL(rtc_set_mmss); |
101 | 102 | ||
102 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 103 | static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
103 | { | 104 | { |
104 | int err; | 105 | int err; |
105 | 106 | ||
@@ -119,6 +120,87 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
119 | mutex_unlock(&rtc->ops_lock); | 120 | mutex_unlock(&rtc->ops_lock); |
120 | return err; | 121 | return err; |
121 | } | 122 | } |
123 | |||
124 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
125 | { | ||
126 | int err; | ||
127 | struct rtc_time before, now; | ||
128 | int first_time = 1; | ||
129 | |||
130 | /* The lower level RTC driver may not be capable of filling | ||
131 | * in all fields of the rtc_time struct (eg. rtc-cmos), | ||
132 | * and so might instead return -1 in some fields. | ||
133 | * We deal with that here by grabbing a current RTC timestamp | ||
134 | * and using values from that for any missing (-1) values. | ||
135 | * | ||
136 | * But this can be racey, because some fields of the RTC timestamp | ||
137 | * may have wrapped in the interval since we read the RTC alarm, | ||
138 | * which would lead to us inserting inconsistent values in place | ||
139 | * of the -1 fields. | ||
140 | * | ||
141 | * Reading the alarm and timestamp in the reverse sequence | ||
142 | * would have the same race condition, and not solve the issue. | ||
143 | * | ||
144 | * So, we must first read the RTC timestamp, | ||
145 | * then read the RTC alarm value, | ||
146 | * and then read a second RTC timestamp. | ||
147 | * | ||
148 | * If any fields of the second timestamp have changed | ||
149 | * when compared with the first timestamp, then we know | ||
150 | * our timestamp may be inconsistent with that used by | ||
151 | * the low-level rtc_read_alarm_internal() function. | ||
152 | * | ||
153 | * So, when the two timestamps disagree, we just loop and do | ||
154 | * the process again to get a fully consistent set of values. | ||
155 | * | ||
156 | * This could all instead be done in the lower level driver, | ||
157 | * but since more than one lower level RTC implementation needs it, | ||
158 | * then it's probably best best to do it here instead of there.. | ||
159 | */ | ||
160 | |||
161 | /* Get the "before" timestamp */ | ||
162 | err = rtc_read_time(rtc, &before); | ||
163 | if (err < 0) | ||
164 | return err; | ||
165 | do { | ||
166 | if (!first_time) | ||
167 | memcpy(&before, &now, sizeof(struct rtc_time)); | ||
168 | first_time = 0; | ||
169 | |||
170 | /* get the RTC alarm values, which may be incomplete */ | ||
171 | err = rtc_read_alarm_internal(rtc, alarm); | ||
172 | if (err) | ||
173 | return err; | ||
174 | if (!alarm->enabled) | ||
175 | return 0; | ||
176 | |||
177 | /* get the "after" timestamp, to detect wrapped fields */ | ||
178 | err = rtc_read_time(rtc, &now); | ||
179 | if (err < 0) | ||
180 | return err; | ||
181 | |||
182 | /* note that tm_sec is a "don't care" value here: */ | ||
183 | } while ( before.tm_min != now.tm_min | ||
184 | || before.tm_hour != now.tm_hour | ||
185 | || before.tm_mon != now.tm_mon | ||
186 | || before.tm_year != now.tm_year | ||
187 | || before.tm_isdst != now.tm_isdst); | ||
188 | |||
189 | /* Fill in any missing alarm fields using the timestamp */ | ||
190 | if (alarm->time.tm_sec == -1) | ||
191 | alarm->time.tm_sec = now.tm_sec; | ||
192 | if (alarm->time.tm_min == -1) | ||
193 | alarm->time.tm_min = now.tm_min; | ||
194 | if (alarm->time.tm_hour == -1) | ||
195 | alarm->time.tm_hour = now.tm_hour; | ||
196 | if (alarm->time.tm_mday == -1) | ||
197 | alarm->time.tm_mday = now.tm_mday; | ||
198 | if (alarm->time.tm_mon == -1) | ||
199 | alarm->time.tm_mon = now.tm_mon; | ||
200 | if (alarm->time.tm_year == -1) | ||
201 | alarm->time.tm_year = now.tm_year; | ||
202 | return 0; | ||
203 | } | ||
122 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | 204 | EXPORT_SYMBOL_GPL(rtc_read_alarm); |
123 | 205 | ||
124 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 206 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
@@ -210,6 +292,10 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) | |||
210 | if (task == NULL || task->func == NULL) | 292 | if (task == NULL || task->func == NULL) |
211 | return -EINVAL; | 293 | return -EINVAL; |
212 | 294 | ||
295 | /* Cannot register while the char dev is in use */ | ||
296 | if (!(mutex_trylock(&rtc->char_lock))) | ||
297 | return -EBUSY; | ||
298 | |||
213 | spin_lock_irq(&rtc->irq_task_lock); | 299 | spin_lock_irq(&rtc->irq_task_lock); |
214 | if (rtc->irq_task == NULL) { | 300 | if (rtc->irq_task == NULL) { |
215 | rtc->irq_task = task; | 301 | rtc->irq_task = task; |
@@ -217,13 +303,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) | |||
217 | } | 303 | } |
218 | spin_unlock_irq(&rtc->irq_task_lock); | 304 | spin_unlock_irq(&rtc->irq_task_lock); |
219 | 305 | ||
306 | mutex_unlock(&rtc->char_lock); | ||
307 | |||
220 | return retval; | 308 | return retval; |
221 | } | 309 | } |
222 | EXPORT_SYMBOL_GPL(rtc_irq_register); | 310 | EXPORT_SYMBOL_GPL(rtc_irq_register); |
223 | 311 | ||
224 | void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) | 312 | void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) |
225 | { | 313 | { |
226 | |||
227 | spin_lock_irq(&rtc->irq_task_lock); | 314 | spin_lock_irq(&rtc->irq_task_lock); |
228 | if (rtc->irq_task == task) | 315 | if (rtc->irq_task == task) |
229 | rtc->irq_task = NULL; | 316 | rtc->irq_task = NULL; |
@@ -231,6 +318,16 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) | |||
231 | } | 318 | } |
232 | EXPORT_SYMBOL_GPL(rtc_irq_unregister); | 319 | EXPORT_SYMBOL_GPL(rtc_irq_unregister); |
233 | 320 | ||
321 | /** | ||
322 | * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs | ||
323 | * @rtc: the rtc device | ||
324 | * @task: currently registered with rtc_irq_register() | ||
325 | * @enabled: true to enable periodic IRQs | ||
326 | * Context: any | ||
327 | * | ||
328 | * Note that rtc_irq_set_freq() should previously have been used to | ||
329 | * specify the desired frequency of periodic IRQ task->func() callbacks. | ||
330 | */ | ||
234 | int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) | 331 | int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) |
235 | { | 332 | { |
236 | int err = 0; | 333 | int err = 0; |
@@ -240,8 +337,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
240 | return -ENXIO; | 337 | return -ENXIO; |
241 | 338 | ||
242 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 339 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
340 | if (rtc->irq_task != NULL && task == NULL) | ||
341 | err = -EBUSY; | ||
243 | if (rtc->irq_task != task) | 342 | if (rtc->irq_task != task) |
244 | err = -ENXIO; | 343 | err = -EACCES; |
245 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | 344 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); |
246 | 345 | ||
247 | if (err == 0) | 346 | if (err == 0) |
@@ -251,6 +350,16 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
251 | } | 350 | } |
252 | EXPORT_SYMBOL_GPL(rtc_irq_set_state); | 351 | EXPORT_SYMBOL_GPL(rtc_irq_set_state); |
253 | 352 | ||
353 | /** | ||
354 | * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ | ||
355 | * @rtc: the rtc device | ||
356 | * @task: currently registered with rtc_irq_register() | ||
357 | * @freq: positive frequency with which task->func() will be called | ||
358 | * Context: any | ||
359 | * | ||
360 | * Note that rtc_irq_set_state() is used to enable or disable the | ||
361 | * periodic IRQs. | ||
362 | */ | ||
254 | int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | 363 | int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) |
255 | { | 364 | { |
256 | int err = 0; | 365 | int err = 0; |
@@ -259,9 +368,14 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
259 | if (rtc->ops->irq_set_freq == NULL) | 368 | if (rtc->ops->irq_set_freq == NULL) |
260 | return -ENXIO; | 369 | return -ENXIO; |
261 | 370 | ||
371 | if (!is_power_of_2(freq)) | ||
372 | return -EINVAL; | ||
373 | |||
262 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 374 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
375 | if (rtc->irq_task != NULL && task == NULL) | ||
376 | err = -EBUSY; | ||
263 | if (rtc->irq_task != task) | 377 | if (rtc->irq_task != task) |
264 | err = -ENXIO; | 378 | err = -EACCES; |
265 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | 379 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); |
266 | 380 | ||
267 | if (err == 0) { | 381 | if (err == 0) { |
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 5d760bb6c2cd..e3fe83a23cf7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -246,11 +246,9 @@ static int cmos_irq_set_freq(struct device *dev, int freq) | |||
246 | 246 | ||
247 | /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ | 247 | /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ |
248 | f = ffs(freq); | 248 | f = ffs(freq); |
249 | if (f != 0) { | 249 | if (f-- > 16) |
250 | if (f-- > 16 || freq != (1 << f)) | 250 | return -EINVAL; |
251 | return -EINVAL; | 251 | f = 16 - f; |
252 | f = 16 - f; | ||
253 | } | ||
254 | 252 | ||
255 | spin_lock_irqsave(&rtc_lock, flags); | 253 | spin_lock_irqsave(&rtc_lock, flags); |
256 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); | 254 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); |
@@ -435,6 +433,19 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) | |||
435 | if (!ports) | 433 | if (!ports) |
436 | return -ENODEV; | 434 | return -ENODEV; |
437 | 435 | ||
436 | /* Claim I/O ports ASAP, minimizing conflict with legacy driver. | ||
437 | * | ||
438 | * REVISIT non-x86 systems may instead use memory space resources | ||
439 | * (needing ioremap etc), not i/o space resources like this ... | ||
440 | */ | ||
441 | ports = request_region(ports->start, | ||
442 | ports->end + 1 - ports->start, | ||
443 | driver_name); | ||
444 | if (!ports) { | ||
445 | dev_dbg(dev, "i/o registers already in use\n"); | ||
446 | return -EBUSY; | ||
447 | } | ||
448 | |||
438 | cmos_rtc.irq = rtc_irq; | 449 | cmos_rtc.irq = rtc_irq; |
439 | cmos_rtc.iomem = ports; | 450 | cmos_rtc.iomem = ports; |
440 | 451 | ||
@@ -456,24 +467,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) | |||
456 | 467 | ||
457 | cmos_rtc.rtc = rtc_device_register(driver_name, dev, | 468 | cmos_rtc.rtc = rtc_device_register(driver_name, dev, |
458 | &cmos_rtc_ops, THIS_MODULE); | 469 | &cmos_rtc_ops, THIS_MODULE); |
459 | if (IS_ERR(cmos_rtc.rtc)) | 470 | if (IS_ERR(cmos_rtc.rtc)) { |
460 | return PTR_ERR(cmos_rtc.rtc); | 471 | retval = PTR_ERR(cmos_rtc.rtc); |
472 | goto cleanup0; | ||
473 | } | ||
461 | 474 | ||
462 | cmos_rtc.dev = dev; | 475 | cmos_rtc.dev = dev; |
463 | dev_set_drvdata(dev, &cmos_rtc); | 476 | dev_set_drvdata(dev, &cmos_rtc); |
464 | |||
465 | /* platform and pnp busses handle resources incompatibly. | ||
466 | * | ||
467 | * REVISIT for non-x86 systems we may need to handle io memory | ||
468 | * resources: ioremap them, and request_mem_region(). | ||
469 | */ | ||
470 | if (is_pnp()) { | ||
471 | retval = request_resource(&ioport_resource, ports); | ||
472 | if (retval < 0) { | ||
473 | dev_dbg(dev, "i/o registers already in use\n"); | ||
474 | goto cleanup0; | ||
475 | } | ||
476 | } | ||
477 | rename_region(ports, cmos_rtc.rtc->dev.bus_id); | 477 | rename_region(ports, cmos_rtc.rtc->dev.bus_id); |
478 | 478 | ||
479 | spin_lock_irq(&rtc_lock); | 479 | spin_lock_irq(&rtc_lock); |
@@ -536,9 +536,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) | |||
536 | return 0; | 536 | return 0; |
537 | 537 | ||
538 | cleanup1: | 538 | cleanup1: |
539 | rename_region(ports, NULL); | 539 | cmos_rtc.dev = NULL; |
540 | cleanup0: | ||
541 | rtc_device_unregister(cmos_rtc.rtc); | 540 | rtc_device_unregister(cmos_rtc.rtc); |
541 | cleanup0: | ||
542 | release_region(ports->start, ports->end + 1 - ports->start); | ||
542 | return retval; | 543 | return retval; |
543 | } | 544 | } |
544 | 545 | ||
@@ -557,19 +558,21 @@ static void cmos_do_shutdown(void) | |||
557 | static void __exit cmos_do_remove(struct device *dev) | 558 | static void __exit cmos_do_remove(struct device *dev) |
558 | { | 559 | { |
559 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 560 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
561 | struct resource *ports; | ||
560 | 562 | ||
561 | cmos_do_shutdown(); | 563 | cmos_do_shutdown(); |
562 | 564 | ||
563 | if (is_pnp()) | ||
564 | release_resource(cmos->iomem); | ||
565 | rename_region(cmos->iomem, NULL); | ||
566 | |||
567 | if (is_valid_irq(cmos->irq)) | 565 | if (is_valid_irq(cmos->irq)) |
568 | free_irq(cmos->irq, cmos_rtc.rtc); | 566 | free_irq(cmos->irq, cmos->rtc); |
569 | 567 | ||
570 | rtc_device_unregister(cmos_rtc.rtc); | 568 | rtc_device_unregister(cmos->rtc); |
569 | cmos->rtc = NULL; | ||
571 | 570 | ||
572 | cmos_rtc.dev = NULL; | 571 | ports = cmos->iomem; |
572 | release_region(ports->start, ports->end + 1 - ports->start); | ||
573 | cmos->iomem = NULL; | ||
574 | |||
575 | cmos->dev = NULL; | ||
573 | dev_set_drvdata(dev, NULL); | 576 | dev_set_drvdata(dev, NULL); |
574 | } | 577 | } |
575 | 578 | ||
@@ -656,7 +659,8 @@ static int cmos_resume(struct device *dev) | |||
656 | /*----------------------------------------------------------------*/ | 659 | /*----------------------------------------------------------------*/ |
657 | 660 | ||
658 | /* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, | 661 | /* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, |
659 | * the device node will always be created as a PNPACPI device. | 662 | * the device node will always be created as a PNPACPI device. Plus |
663 | * pre-ACPI PCs probably list it in the PNPBIOS tables. | ||
660 | */ | 664 | */ |
661 | 665 | ||
662 | #ifdef CONFIG_PNP | 666 | #ifdef CONFIG_PNP |
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 005fff3a3508..814583bd2fe7 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
@@ -142,7 +142,7 @@ static int set_uie(struct rtc_device *rtc) | |||
142 | static ssize_t | 142 | static ssize_t |
143 | rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 143 | rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
144 | { | 144 | { |
145 | struct rtc_device *rtc = to_rtc_device(file->private_data); | 145 | struct rtc_device *rtc = file->private_data; |
146 | 146 | ||
147 | DECLARE_WAITQUEUE(wait, current); | 147 | DECLARE_WAITQUEUE(wait, current); |
148 | unsigned long data; | 148 | unsigned long data; |
@@ -196,7 +196,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
196 | 196 | ||
197 | static unsigned int rtc_dev_poll(struct file *file, poll_table *wait) | 197 | static unsigned int rtc_dev_poll(struct file *file, poll_table *wait) |
198 | { | 198 | { |
199 | struct rtc_device *rtc = to_rtc_device(file->private_data); | 199 | struct rtc_device *rtc = file->private_data; |
200 | unsigned long data; | 200 | unsigned long data; |
201 | 201 | ||
202 | poll_wait(file, &rtc->irq_queue, wait); | 202 | poll_wait(file, &rtc->irq_queue, wait); |
@@ -233,22 +233,12 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
233 | break; | 233 | break; |
234 | 234 | ||
235 | case RTC_PIE_ON: | 235 | case RTC_PIE_ON: |
236 | if (!capable(CAP_SYS_RESOURCE)) | 236 | if (rtc->irq_freq > rtc->max_user_freq && |
237 | !capable(CAP_SYS_RESOURCE)) | ||
237 | return -EACCES; | 238 | return -EACCES; |
238 | break; | 239 | break; |
239 | } | 240 | } |
240 | 241 | ||
241 | /* avoid conflicting IRQ users */ | ||
242 | if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { | ||
243 | spin_lock_irq(&rtc->irq_task_lock); | ||
244 | if (rtc->irq_task) | ||
245 | err = -EBUSY; | ||
246 | spin_unlock_irq(&rtc->irq_task_lock); | ||
247 | |||
248 | if (err < 0) | ||
249 | return err; | ||
250 | } | ||
251 | |||
252 | /* try the driver's ioctl interface */ | 242 | /* try the driver's ioctl interface */ |
253 | if (ops->ioctl) { | 243 | if (ops->ioctl) { |
254 | err = ops->ioctl(rtc->dev.parent, cmd, arg); | 244 | err = ops->ioctl(rtc->dev.parent, cmd, arg); |
@@ -338,18 +328,20 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
338 | err = rtc_set_time(rtc, &tm); | 328 | err = rtc_set_time(rtc, &tm); |
339 | break; | 329 | break; |
340 | 330 | ||
341 | case RTC_IRQP_READ: | 331 | case RTC_PIE_ON: |
342 | if (ops->irq_set_freq) | 332 | err = rtc_irq_set_state(rtc, NULL, 1); |
343 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); | 333 | break; |
344 | else | 334 | |
345 | err = -ENOTTY; | 335 | case RTC_PIE_OFF: |
336 | err = rtc_irq_set_state(rtc, NULL, 0); | ||
346 | break; | 337 | break; |
347 | 338 | ||
348 | case RTC_IRQP_SET: | 339 | case RTC_IRQP_SET: |
349 | if (ops->irq_set_freq) | 340 | err = rtc_irq_set_freq(rtc, NULL, arg); |
350 | err = rtc_irq_set_freq(rtc, rtc->irq_task, arg); | 341 | break; |
351 | else | 342 | |
352 | err = -ENOTTY; | 343 | case RTC_IRQP_READ: |
344 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); | ||
353 | break; | 345 | break; |
354 | 346 | ||
355 | #if 0 | 347 | #if 0 |
@@ -405,7 +397,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
405 | 397 | ||
406 | static int rtc_dev_release(struct inode *inode, struct file *file) | 398 | static int rtc_dev_release(struct inode *inode, struct file *file) |
407 | { | 399 | { |
408 | struct rtc_device *rtc = to_rtc_device(file->private_data); | 400 | struct rtc_device *rtc = file->private_data; |
409 | 401 | ||
410 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 402 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
411 | clear_uie(rtc); | 403 | clear_uie(rtc); |
@@ -419,7 +411,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) | |||
419 | 411 | ||
420 | static int rtc_dev_fasync(int fd, struct file *file, int on) | 412 | static int rtc_dev_fasync(int fd, struct file *file, int on) |
421 | { | 413 | { |
422 | struct rtc_device *rtc = to_rtc_device(file->private_data); | 414 | struct rtc_device *rtc = file->private_data; |
423 | return fasync_helper(fd, file, on, &rtc->async_queue); | 415 | return fasync_helper(fd, file, on, &rtc->async_queue); |
424 | } | 416 | } |
425 | 417 | ||
@@ -449,8 +441,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) | |||
449 | rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); | 441 | rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); |
450 | 442 | ||
451 | mutex_init(&rtc->char_lock); | 443 | mutex_init(&rtc->char_lock); |
452 | spin_lock_init(&rtc->irq_lock); | ||
453 | init_waitqueue_head(&rtc->irq_queue); | ||
454 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 444 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
455 | INIT_WORK(&rtc->uie_task, rtc_uie_task); | 445 | INIT_WORK(&rtc->uie_task, rtc_uie_task); |
456 | setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); | 446 | setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); |
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c new file mode 100644 index 000000000000..45bda186befc --- /dev/null +++ b/drivers/rtc/rtc-ds1374.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C | ||
3 | * | ||
4 | * Based on code by Randy Vinson <rvinson@mvista.com>, | ||
5 | * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>. | ||
6 | * | ||
7 | * Copyright (C) 2006-2007 Freescale Semiconductor | ||
8 | * | ||
9 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
10 | * the terms of the GNU General Public License version 2. This program | ||
11 | * is licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | */ | ||
14 | /* | ||
15 | * It would be more efficient to use i2c msgs/i2c_transfer directly but, as | ||
16 | * recommened in .../Documentation/i2c/writing-clients section | ||
17 | * "Sending and receiving", using SMBus level communication is preferred. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/rtc.h> | ||
25 | #include <linux/bcd.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | |||
28 | #define DS1374_REG_TOD0 0x00 /* Time of Day */ | ||
29 | #define DS1374_REG_TOD1 0x01 | ||
30 | #define DS1374_REG_TOD2 0x02 | ||
31 | #define DS1374_REG_TOD3 0x03 | ||
32 | #define DS1374_REG_WDALM0 0x04 /* Watchdog/Alarm */ | ||
33 | #define DS1374_REG_WDALM1 0x05 | ||
34 | #define DS1374_REG_WDALM2 0x06 | ||
35 | #define DS1374_REG_CR 0x07 /* Control */ | ||
36 | #define DS1374_REG_CR_AIE 0x01 /* Alarm Int. Enable */ | ||
37 | #define DS1374_REG_CR_WDALM 0x20 /* 1=Watchdog, 0=Alarm */ | ||
38 | #define DS1374_REG_CR_WACE 0x40 /* WD/Alarm counter enable */ | ||
39 | #define DS1374_REG_SR 0x08 /* Status */ | ||
40 | #define DS1374_REG_SR_OSF 0x80 /* Oscillator Stop Flag */ | ||
41 | #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ | ||
42 | #define DS1374_REG_TCR 0x09 /* Trickle Charge */ | ||
43 | |||
44 | struct ds1374 { | ||
45 | struct i2c_client *client; | ||
46 | struct rtc_device *rtc; | ||
47 | struct work_struct work; | ||
48 | |||
49 | /* The mutex protects alarm operations, and prevents a race | ||
50 | * between the enable_irq() in the workqueue and the free_irq() | ||
51 | * in the remove function. | ||
52 | */ | ||
53 | struct mutex mutex; | ||
54 | int exiting; | ||
55 | }; | ||
56 | |||
57 | static struct i2c_driver ds1374_driver; | ||
58 | |||
59 | static int ds1374_read_rtc(struct i2c_client *client, u32 *time, | ||
60 | int reg, int nbytes) | ||
61 | { | ||
62 | u8 buf[4]; | ||
63 | int ret; | ||
64 | int i; | ||
65 | |||
66 | if (nbytes > 4) { | ||
67 | WARN_ON(1); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); | ||
72 | |||
73 | if (ret < 0) | ||
74 | return ret; | ||
75 | if (ret < nbytes) | ||
76 | return -EIO; | ||
77 | |||
78 | for (i = nbytes - 1, *time = 0; i >= 0; i--) | ||
79 | *time = (*time << 8) | buf[i]; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int ds1374_write_rtc(struct i2c_client *client, u32 time, | ||
85 | int reg, int nbytes) | ||
86 | { | ||
87 | u8 buf[4]; | ||
88 | int i; | ||
89 | |||
90 | if (nbytes > 4) { | ||
91 | WARN_ON(1); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | for (i = 0; i < nbytes; i++) { | ||
96 | buf[i] = time & 0xff; | ||
97 | time >>= 8; | ||
98 | } | ||
99 | |||
100 | return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); | ||
101 | } | ||
102 | |||
103 | static int ds1374_check_rtc_status(struct i2c_client *client) | ||
104 | { | ||
105 | int ret = 0; | ||
106 | int control, stat; | ||
107 | |||
108 | stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); | ||
109 | if (stat < 0) | ||
110 | return stat; | ||
111 | |||
112 | if (stat & DS1374_REG_SR_OSF) | ||
113 | dev_warn(&client->dev, | ||
114 | "oscillator discontinuity flagged, " | ||
115 | "time unreliable\n"); | ||
116 | |||
117 | stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF); | ||
118 | |||
119 | ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); | ||
120 | if (ret < 0) | ||
121 | return ret; | ||
122 | |||
123 | /* If the alarm is pending, clear it before requesting | ||
124 | * the interrupt, so an interrupt event isn't reported | ||
125 | * before everything is initialized. | ||
126 | */ | ||
127 | |||
128 | control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
129 | if (control < 0) | ||
130 | return control; | ||
131 | |||
132 | control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); | ||
133 | return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); | ||
134 | } | ||
135 | |||
136 | static int ds1374_read_time(struct device *dev, struct rtc_time *time) | ||
137 | { | ||
138 | struct i2c_client *client = to_i2c_client(dev); | ||
139 | u32 itime; | ||
140 | int ret; | ||
141 | |||
142 | ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4); | ||
143 | if (!ret) | ||
144 | rtc_time_to_tm(itime, time); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int ds1374_set_time(struct device *dev, struct rtc_time *time) | ||
150 | { | ||
151 | struct i2c_client *client = to_i2c_client(dev); | ||
152 | unsigned long itime; | ||
153 | |||
154 | rtc_tm_to_time(time, &itime); | ||
155 | return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); | ||
156 | } | ||
157 | |||
158 | /* The ds1374 has a decrementer for an alarm, rather than a comparator. | ||
159 | * If the time of day is changed, then the alarm will need to be | ||
160 | * reset. | ||
161 | */ | ||
162 | static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
163 | { | ||
164 | struct i2c_client *client = to_i2c_client(dev); | ||
165 | struct ds1374 *ds1374 = i2c_get_clientdata(client); | ||
166 | u32 now, cur_alarm; | ||
167 | int cr, sr; | ||
168 | int ret = 0; | ||
169 | |||
170 | if (client->irq < 0) | ||
171 | return -EINVAL; | ||
172 | |||
173 | mutex_lock(&ds1374->mutex); | ||
174 | |||
175 | cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
176 | if (ret < 0) | ||
177 | goto out; | ||
178 | |||
179 | sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR); | ||
180 | if (ret < 0) | ||
181 | goto out; | ||
182 | |||
183 | ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4); | ||
184 | if (ret) | ||
185 | goto out; | ||
186 | |||
187 | ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3); | ||
188 | if (ret) | ||
189 | goto out; | ||
190 | |||
191 | rtc_time_to_tm(now + cur_alarm, &alarm->time); | ||
192 | alarm->enabled = !!(cr & DS1374_REG_CR_WACE); | ||
193 | alarm->pending = !!(sr & DS1374_REG_SR_AF); | ||
194 | |||
195 | out: | ||
196 | mutex_unlock(&ds1374->mutex); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
201 | { | ||
202 | struct i2c_client *client = to_i2c_client(dev); | ||
203 | struct ds1374 *ds1374 = i2c_get_clientdata(client); | ||
204 | struct rtc_time now; | ||
205 | unsigned long new_alarm, itime; | ||
206 | int cr; | ||
207 | int ret = 0; | ||
208 | |||
209 | if (client->irq < 0) | ||
210 | return -EINVAL; | ||
211 | |||
212 | ret = ds1374_read_time(dev, &now); | ||
213 | if (ret < 0) | ||
214 | return ret; | ||
215 | |||
216 | rtc_tm_to_time(&alarm->time, &new_alarm); | ||
217 | rtc_tm_to_time(&now, &itime); | ||
218 | |||
219 | new_alarm -= itime; | ||
220 | |||
221 | /* This can happen due to races, in addition to dates that are | ||
222 | * truly in the past. To avoid requiring the caller to check for | ||
223 | * races, dates in the past are assumed to be in the recent past | ||
224 | * (i.e. not something that we'd rather the caller know about via | ||
225 | * an error), and the alarm is set to go off as soon as possible. | ||
226 | */ | ||
227 | if (new_alarm <= 0) | ||
228 | new_alarm = 1; | ||
229 | |||
230 | mutex_lock(&ds1374->mutex); | ||
231 | |||
232 | ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
233 | if (ret < 0) | ||
234 | goto out; | ||
235 | |||
236 | /* Disable any existing alarm before setting the new one | ||
237 | * (or lack thereof). */ | ||
238 | cr &= ~DS1374_REG_CR_WACE; | ||
239 | |||
240 | ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); | ||
241 | if (ret < 0) | ||
242 | goto out; | ||
243 | |||
244 | ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3); | ||
245 | if (ret) | ||
246 | goto out; | ||
247 | |||
248 | if (alarm->enabled) { | ||
249 | cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; | ||
250 | cr &= ~DS1374_REG_CR_WDALM; | ||
251 | |||
252 | ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); | ||
253 | } | ||
254 | |||
255 | out: | ||
256 | mutex_unlock(&ds1374->mutex); | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static irqreturn_t ds1374_irq(int irq, void *dev_id) | ||
261 | { | ||
262 | struct i2c_client *client = dev_id; | ||
263 | struct ds1374 *ds1374 = i2c_get_clientdata(client); | ||
264 | |||
265 | disable_irq_nosync(irq); | ||
266 | schedule_work(&ds1374->work); | ||
267 | return IRQ_HANDLED; | ||
268 | } | ||
269 | |||
270 | static void ds1374_work(struct work_struct *work) | ||
271 | { | ||
272 | struct ds1374 *ds1374 = container_of(work, struct ds1374, work); | ||
273 | struct i2c_client *client = ds1374->client; | ||
274 | int stat, control; | ||
275 | |||
276 | mutex_lock(&ds1374->mutex); | ||
277 | |||
278 | stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); | ||
279 | if (stat < 0) | ||
280 | return; | ||
281 | |||
282 | if (stat & DS1374_REG_SR_AF) { | ||
283 | stat &= ~DS1374_REG_SR_AF; | ||
284 | i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); | ||
285 | |||
286 | control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
287 | if (control < 0) | ||
288 | goto out; | ||
289 | |||
290 | control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); | ||
291 | i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); | ||
292 | |||
293 | /* rtc_update_irq() assumes that it is called | ||
294 | * from IRQ-disabled context. | ||
295 | */ | ||
296 | local_irq_disable(); | ||
297 | rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); | ||
298 | local_irq_enable(); | ||
299 | } | ||
300 | |||
301 | out: | ||
302 | if (!ds1374->exiting) | ||
303 | enable_irq(client->irq); | ||
304 | |||
305 | mutex_unlock(&ds1374->mutex); | ||
306 | } | ||
307 | |||
308 | static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
309 | { | ||
310 | struct i2c_client *client = to_i2c_client(dev); | ||
311 | struct ds1374 *ds1374 = i2c_get_clientdata(client); | ||
312 | int ret = -ENOIOCTLCMD; | ||
313 | |||
314 | mutex_lock(&ds1374->mutex); | ||
315 | |||
316 | switch (cmd) { | ||
317 | case RTC_AIE_OFF: | ||
318 | ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
319 | if (ret < 0) | ||
320 | goto out; | ||
321 | |||
322 | ret &= ~DS1374_REG_CR_WACE; | ||
323 | |||
324 | ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); | ||
325 | if (ret < 0) | ||
326 | goto out; | ||
327 | |||
328 | break; | ||
329 | |||
330 | case RTC_AIE_ON: | ||
331 | ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); | ||
332 | if (ret < 0) | ||
333 | goto out; | ||
334 | |||
335 | ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; | ||
336 | ret &= ~DS1374_REG_CR_WDALM; | ||
337 | |||
338 | ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); | ||
339 | if (ret < 0) | ||
340 | goto out; | ||
341 | |||
342 | break; | ||
343 | } | ||
344 | |||
345 | out: | ||
346 | mutex_unlock(&ds1374->mutex); | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | static const struct rtc_class_ops ds1374_rtc_ops = { | ||
351 | .read_time = ds1374_read_time, | ||
352 | .set_time = ds1374_set_time, | ||
353 | .read_alarm = ds1374_read_alarm, | ||
354 | .set_alarm = ds1374_set_alarm, | ||
355 | .ioctl = ds1374_ioctl, | ||
356 | }; | ||
357 | |||
358 | static int ds1374_probe(struct i2c_client *client) | ||
359 | { | ||
360 | struct ds1374 *ds1374; | ||
361 | int ret; | ||
362 | |||
363 | ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL); | ||
364 | if (!ds1374) | ||
365 | return -ENOMEM; | ||
366 | |||
367 | ds1374->client = client; | ||
368 | i2c_set_clientdata(client, ds1374); | ||
369 | |||
370 | INIT_WORK(&ds1374->work, ds1374_work); | ||
371 | mutex_init(&ds1374->mutex); | ||
372 | |||
373 | ret = ds1374_check_rtc_status(client); | ||
374 | if (ret) | ||
375 | goto out_free; | ||
376 | |||
377 | if (client->irq >= 0) { | ||
378 | ret = request_irq(client->irq, ds1374_irq, 0, | ||
379 | "ds1374", client); | ||
380 | if (ret) { | ||
381 | dev_err(&client->dev, "unable to request IRQ\n"); | ||
382 | goto out_free; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | ds1374->rtc = rtc_device_register(client->name, &client->dev, | ||
387 | &ds1374_rtc_ops, THIS_MODULE); | ||
388 | if (IS_ERR(ds1374->rtc)) { | ||
389 | ret = PTR_ERR(ds1374->rtc); | ||
390 | dev_err(&client->dev, "unable to register the class device\n"); | ||
391 | goto out_irq; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | |||
396 | out_irq: | ||
397 | if (client->irq >= 0) | ||
398 | free_irq(client->irq, client); | ||
399 | |||
400 | out_free: | ||
401 | i2c_set_clientdata(client, NULL); | ||
402 | kfree(ds1374); | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | static int __devexit ds1374_remove(struct i2c_client *client) | ||
407 | { | ||
408 | struct ds1374 *ds1374 = i2c_get_clientdata(client); | ||
409 | |||
410 | if (client->irq >= 0) { | ||
411 | mutex_lock(&ds1374->mutex); | ||
412 | ds1374->exiting = 1; | ||
413 | mutex_unlock(&ds1374->mutex); | ||
414 | |||
415 | free_irq(client->irq, client); | ||
416 | flush_scheduled_work(); | ||
417 | } | ||
418 | |||
419 | rtc_device_unregister(ds1374->rtc); | ||
420 | i2c_set_clientdata(client, NULL); | ||
421 | kfree(ds1374); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static struct i2c_driver ds1374_driver = { | ||
426 | .driver = { | ||
427 | .name = "rtc-ds1374", | ||
428 | .owner = THIS_MODULE, | ||
429 | }, | ||
430 | .probe = ds1374_probe, | ||
431 | .remove = __devexit_p(ds1374_remove), | ||
432 | }; | ||
433 | |||
434 | static int __init ds1374_init(void) | ||
435 | { | ||
436 | return i2c_add_driver(&ds1374_driver); | ||
437 | } | ||
438 | |||
439 | static void __exit ds1374_exit(void) | ||
440 | { | ||
441 | i2c_del_driver(&ds1374_driver); | ||
442 | } | ||
443 | |||
444 | module_init(ds1374_init); | ||
445 | module_exit(ds1374_exit); | ||
446 | |||
447 | MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>"); | ||
448 | MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver"); | ||
449 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 5ab3492817d1..bb53c09bad16 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
@@ -395,7 +395,7 @@ static struct platform_driver ds1553_rtc_driver = { | |||
395 | .probe = ds1553_rtc_probe, | 395 | .probe = ds1553_rtc_probe, |
396 | .remove = __devexit_p(ds1553_rtc_remove), | 396 | .remove = __devexit_p(ds1553_rtc_remove), |
397 | .driver = { | 397 | .driver = { |
398 | .name = "ds1553", | 398 | .name = "rtc-ds1553", |
399 | .owner = THIS_MODULE, | 399 | .owner = THIS_MODULE, |
400 | }, | 400 | }, |
401 | }; | 401 | }; |
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 67291b0f8283..c535b78698e2 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c | |||
@@ -251,7 +251,7 @@ static struct platform_driver ds1742_rtc_driver = { | |||
251 | .probe = ds1742_rtc_probe, | 251 | .probe = ds1742_rtc_probe, |
252 | .remove = __devexit_p(ds1742_rtc_remove), | 252 | .remove = __devexit_p(ds1742_rtc_remove), |
253 | .driver = { | 253 | .driver = { |
254 | .name = "ds1742", | 254 | .name = "rtc-ds1742", |
255 | .owner = THIS_MODULE, | 255 | .owner = THIS_MODULE, |
256 | }, | 256 | }, |
257 | }; | 257 | }; |
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index d48b03374586..556d0e7da35b 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c | |||
@@ -332,6 +332,9 @@ static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind) | |||
332 | } | 332 | } |
333 | }; | 333 | }; |
334 | 334 | ||
335 | if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) | ||
336 | return 0; | ||
337 | |||
335 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); | 338 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); |
336 | if (!pcf) | 339 | if (!pcf) |
337 | return -ENOMEM; | 340 | return -ENOMEM; |
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 69df94b44841..6cad0841f3c4 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c | |||
@@ -73,11 +73,35 @@ rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, | |||
73 | return retval; | 73 | return retval; |
74 | } | 74 | } |
75 | 75 | ||
76 | static ssize_t | ||
77 | rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, | ||
78 | char *buf) | ||
79 | { | ||
80 | return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); | ||
81 | } | ||
82 | |||
83 | static ssize_t | ||
84 | rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, | ||
85 | const char *buf, size_t n) | ||
86 | { | ||
87 | struct rtc_device *rtc = to_rtc_device(dev); | ||
88 | unsigned long val = simple_strtoul(buf, NULL, 0); | ||
89 | |||
90 | if (val >= 4096 || val == 0) | ||
91 | return -EINVAL; | ||
92 | |||
93 | rtc->max_user_freq = (int)val; | ||
94 | |||
95 | return n; | ||
96 | } | ||
97 | |||
76 | static struct device_attribute rtc_attrs[] = { | 98 | static struct device_attribute rtc_attrs[] = { |
77 | __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), | 99 | __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), |
78 | __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), | 100 | __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), |
79 | __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), | 101 | __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), |
80 | __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), | 102 | __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), |
103 | __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, | ||
104 | rtc_sysfs_set_max_user_freq), | ||
81 | { }, | 105 | { }, |
82 | }; | 106 | }; |
83 | 107 | ||
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index cdbcaa5ad6cf..abe2bda6ac37 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c | |||
@@ -53,6 +53,11 @@ | |||
53 | #include "scsi.h" | 53 | #include "scsi.h" |
54 | #include <scsi/scsi_host.h> | 54 | #include <scsi/scsi_host.h> |
55 | #include "mac_scsi.h" | 55 | #include "mac_scsi.h" |
56 | |||
57 | /* These control the behaviour of the generic 5380 core */ | ||
58 | #define AUTOSENSE | ||
59 | #define PSEUDO_DMA | ||
60 | |||
56 | #include "NCR5380.h" | 61 | #include "NCR5380.h" |
57 | 62 | ||
58 | #if 0 | 63 | #if 0 |
@@ -571,10 +576,6 @@ static int macscsi_pwrite (struct Scsi_Host *instance, | |||
571 | } | 576 | } |
572 | 577 | ||
573 | 578 | ||
574 | /* These control the behaviour of the generic 5380 core */ | ||
575 | #define AUTOSENSE | ||
576 | #define PSEUDO_DMA | ||
577 | |||
578 | #include "NCR5380.c" | 579 | #include "NCR5380.c" |
579 | 580 | ||
580 | static struct scsi_host_template driver_template = { | 581 | static struct scsi_host_template driver_template = { |
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 1ea1ed82c352..0e357562ce9e 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c | |||
@@ -1036,6 +1036,7 @@ enum pci_board_num_t { | |||
1036 | pbn_b0_2_115200, | 1036 | pbn_b0_2_115200, |
1037 | pbn_b0_4_115200, | 1037 | pbn_b0_4_115200, |
1038 | pbn_b0_5_115200, | 1038 | pbn_b0_5_115200, |
1039 | pbn_b0_8_115200, | ||
1039 | 1040 | ||
1040 | pbn_b0_1_921600, | 1041 | pbn_b0_1_921600, |
1041 | pbn_b0_2_921600, | 1042 | pbn_b0_2_921600, |
@@ -1172,6 +1173,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { | |||
1172 | .base_baud = 115200, | 1173 | .base_baud = 115200, |
1173 | .uart_offset = 8, | 1174 | .uart_offset = 8, |
1174 | }, | 1175 | }, |
1176 | [pbn_b0_8_115200] = { | ||
1177 | .flags = FL_BASE0, | ||
1178 | .num_ports = 8, | ||
1179 | .base_baud = 115200, | ||
1180 | .uart_offset = 8, | ||
1181 | }, | ||
1175 | 1182 | ||
1176 | [pbn_b0_1_921600] = { | 1183 | [pbn_b0_1_921600] = { |
1177 | .flags = FL_BASE0, | 1184 | .flags = FL_BASE0, |
@@ -2566,6 +2573,119 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
2566 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, | 2573 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, |
2567 | PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, | 2574 | PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, |
2568 | 0, 0, pbn_b2_8_921600 }, | 2575 | 0, 0, pbn_b2_8_921600 }, |
2576 | |||
2577 | /* | ||
2578 | * Mainpine series cards: Fairly standard layout but fools | ||
2579 | * parts of the autodetect in some cases and uses otherwise | ||
2580 | * unmatched communications subclasses in the PCI Express case | ||
2581 | */ | ||
2582 | |||
2583 | { /* RockForceDUO */ | ||
2584 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2585 | PCI_VENDOR_ID_MAINPINE, 0x0200, | ||
2586 | 0, 0, pbn_b0_2_115200 }, | ||
2587 | { /* RockForceQUATRO */ | ||
2588 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2589 | PCI_VENDOR_ID_MAINPINE, 0x0300, | ||
2590 | 0, 0, pbn_b0_4_115200 }, | ||
2591 | { /* RockForceDUO+ */ | ||
2592 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2593 | PCI_VENDOR_ID_MAINPINE, 0x0400, | ||
2594 | 0, 0, pbn_b0_2_115200 }, | ||
2595 | { /* RockForceQUATRO+ */ | ||
2596 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2597 | PCI_VENDOR_ID_MAINPINE, 0x0500, | ||
2598 | 0, 0, pbn_b0_4_115200 }, | ||
2599 | { /* RockForce+ */ | ||
2600 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2601 | PCI_VENDOR_ID_MAINPINE, 0x0600, | ||
2602 | 0, 0, pbn_b0_2_115200 }, | ||
2603 | { /* RockForce+ */ | ||
2604 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2605 | PCI_VENDOR_ID_MAINPINE, 0x0700, | ||
2606 | 0, 0, pbn_b0_4_115200 }, | ||
2607 | { /* RockForceOCTO+ */ | ||
2608 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2609 | PCI_VENDOR_ID_MAINPINE, 0x0800, | ||
2610 | 0, 0, pbn_b0_8_115200 }, | ||
2611 | { /* RockForceDUO+ */ | ||
2612 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2613 | PCI_VENDOR_ID_MAINPINE, 0x0C00, | ||
2614 | 0, 0, pbn_b0_2_115200 }, | ||
2615 | { /* RockForceQUARTRO+ */ | ||
2616 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2617 | PCI_VENDOR_ID_MAINPINE, 0x0D00, | ||
2618 | 0, 0, pbn_b0_4_115200 }, | ||
2619 | { /* RockForceOCTO+ */ | ||
2620 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2621 | PCI_VENDOR_ID_MAINPINE, 0x1D00, | ||
2622 | 0, 0, pbn_b0_8_115200 }, | ||
2623 | { /* RockForceD1 */ | ||
2624 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2625 | PCI_VENDOR_ID_MAINPINE, 0x2000, | ||
2626 | 0, 0, pbn_b0_1_115200 }, | ||
2627 | { /* RockForceF1 */ | ||
2628 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2629 | PCI_VENDOR_ID_MAINPINE, 0x2100, | ||
2630 | 0, 0, pbn_b0_1_115200 }, | ||
2631 | { /* RockForceD2 */ | ||
2632 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2633 | PCI_VENDOR_ID_MAINPINE, 0x2200, | ||
2634 | 0, 0, pbn_b0_2_115200 }, | ||
2635 | { /* RockForceF2 */ | ||
2636 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2637 | PCI_VENDOR_ID_MAINPINE, 0x2300, | ||
2638 | 0, 0, pbn_b0_2_115200 }, | ||
2639 | { /* RockForceD4 */ | ||
2640 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2641 | PCI_VENDOR_ID_MAINPINE, 0x2400, | ||
2642 | 0, 0, pbn_b0_4_115200 }, | ||
2643 | { /* RockForceF4 */ | ||
2644 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2645 | PCI_VENDOR_ID_MAINPINE, 0x2500, | ||
2646 | 0, 0, pbn_b0_4_115200 }, | ||
2647 | { /* RockForceD8 */ | ||
2648 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2649 | PCI_VENDOR_ID_MAINPINE, 0x2600, | ||
2650 | 0, 0, pbn_b0_8_115200 }, | ||
2651 | { /* RockForceF8 */ | ||
2652 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2653 | PCI_VENDOR_ID_MAINPINE, 0x2700, | ||
2654 | 0, 0, pbn_b0_8_115200 }, | ||
2655 | { /* IQ Express D1 */ | ||
2656 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2657 | PCI_VENDOR_ID_MAINPINE, 0x3000, | ||
2658 | 0, 0, pbn_b0_1_115200 }, | ||
2659 | { /* IQ Express F1 */ | ||
2660 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2661 | PCI_VENDOR_ID_MAINPINE, 0x3100, | ||
2662 | 0, 0, pbn_b0_1_115200 }, | ||
2663 | { /* IQ Express D2 */ | ||
2664 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2665 | PCI_VENDOR_ID_MAINPINE, 0x3200, | ||
2666 | 0, 0, pbn_b0_2_115200 }, | ||
2667 | { /* IQ Express F2 */ | ||
2668 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2669 | PCI_VENDOR_ID_MAINPINE, 0x3300, | ||
2670 | 0, 0, pbn_b0_2_115200 }, | ||
2671 | { /* IQ Express D4 */ | ||
2672 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2673 | PCI_VENDOR_ID_MAINPINE, 0x3400, | ||
2674 | 0, 0, pbn_b0_4_115200 }, | ||
2675 | { /* IQ Express F4 */ | ||
2676 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2677 | PCI_VENDOR_ID_MAINPINE, 0x3500, | ||
2678 | 0, 0, pbn_b0_4_115200 }, | ||
2679 | { /* IQ Express D8 */ | ||
2680 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2681 | PCI_VENDOR_ID_MAINPINE, 0x3C00, | ||
2682 | 0, 0, pbn_b0_8_115200 }, | ||
2683 | { /* IQ Express F8 */ | ||
2684 | PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, | ||
2685 | PCI_VENDOR_ID_MAINPINE, 0x3D00, | ||
2686 | 0, 0, pbn_b0_8_115200 }, | ||
2687 | |||
2688 | |||
2569 | /* | 2689 | /* |
2570 | * PA Semi PA6T-1682M on-chip UART | 2690 | * PA Semi PA6T-1682M on-chip UART |
2571 | */ | 2691 | */ |
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 301c8c0be9d7..926f58a674a1 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c | |||
@@ -327,6 +327,8 @@ static const struct pnp_device_id pnp_dev_table[] = { | |||
327 | { "WACF004", 0 }, | 327 | { "WACF004", 0 }, |
328 | { "WACF005", 0 }, | 328 | { "WACF005", 0 }, |
329 | { "WACF006", 0 }, | 329 | { "WACF006", 0 }, |
330 | { "WACF007", 0 }, | ||
331 | { "WACF008", 0 }, | ||
330 | /* Compaq touchscreen */ | 332 | /* Compaq touchscreen */ |
331 | { "FPI2002", 0 }, | 333 | { "FPI2002", 0 }, |
332 | /* Fujitsu Stylistic touchscreens */ | 334 | /* Fujitsu Stylistic touchscreens */ |
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 312bef6bd583..7e8724d3571f 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c | |||
@@ -514,6 +514,8 @@ struct tty_driver *serial_driver; | |||
514 | * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128 | 514 | * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128 |
515 | * BUF_SIZE can't be > 128 | 515 | * BUF_SIZE can't be > 128 |
516 | */ | 516 | */ |
517 | #define CRIS_BUF_SIZE 512 | ||
518 | |||
517 | /* Currently 16 descriptors x 128 bytes = 2048 bytes */ | 519 | /* Currently 16 descriptors x 128 bytes = 2048 bytes */ |
518 | #define SERIAL_DESCR_BUF_SIZE 256 | 520 | #define SERIAL_DESCR_BUF_SIZE 256 |
519 | 521 | ||
@@ -2497,55 +2499,18 @@ static void flush_to_flip_buffer(struct e100_serial *info) | |||
2497 | return; | 2499 | return; |
2498 | } | 2500 | } |
2499 | 2501 | ||
2500 | length = tty->flip.count; | 2502 | while ((buffer = info->first_recv_buffer) != NULL) { |
2501 | /* Don't flip more than the ldisc has room for. | ||
2502 | * The return value from ldisc.receive_room(tty) - might not be up to | ||
2503 | * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the | ||
2504 | * processed and not accounted for yet. | ||
2505 | * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way. | ||
2506 | * Lets buffer data here and let flow control take care of it. | ||
2507 | * Since we normally flip large chunks, the ldisc don't react | ||
2508 | * with throttle until too late if we flip to much. | ||
2509 | */ | ||
2510 | max_flip_size = tty->ldisc.receive_room(tty); | ||
2511 | if (max_flip_size < 0) | ||
2512 | max_flip_size = 0; | ||
2513 | if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */ | ||
2514 | length + info->recv_cnt + /* We have this queued */ | ||
2515 | 2*SERIAL_DESCR_BUF_SIZE + /* This could be on the way */ | ||
2516 | TTY_THRESHOLD_THROTTLE)) { /* Some slack */ | ||
2517 | /* check TTY_THROTTLED first so it indicates our state */ | ||
2518 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) { | ||
2519 | DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size)); | ||
2520 | rs_throttle(tty); | ||
2521 | } | ||
2522 | #if 0 | ||
2523 | else if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */ | ||
2524 | length + info->recv_cnt + /* We have this queued */ | ||
2525 | SERIAL_DESCR_BUF_SIZE + /* This could be on the way */ | ||
2526 | TTY_THRESHOLD_THROTTLE)) { /* Some slack */ | ||
2527 | DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size)); | ||
2528 | rs_throttle(tty); | ||
2529 | } | ||
2530 | #endif | ||
2531 | } | ||
2532 | |||
2533 | if (max_flip_size > TTY_FLIPBUF_SIZE) | ||
2534 | max_flip_size = TTY_FLIPBUF_SIZE; | ||
2535 | |||
2536 | while ((buffer = info->first_recv_buffer) && length < max_flip_size) { | ||
2537 | unsigned int count = buffer->length; | 2503 | unsigned int count = buffer->length; |
2538 | 2504 | ||
2539 | if (length + count > max_flip_size) | 2505 | count = tty_buffer_request_room(tty, count); |
2540 | count = max_flip_size - length; | 2506 | if (count == 0) /* Throttle ?? */ |
2507 | break; | ||
2541 | 2508 | ||
2542 | memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); | 2509 | if (count > 1) |
2543 | memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); | 2510 | tty_insert_flip_strings(tty, buffer->buffer, count - 1); |
2544 | tty->flip.flag_buf_ptr[length] = buffer->error; | 2511 | tty_insert_flip_char(tty, buffer->buffer[count-1], buffer->error); |
2545 | 2512 | ||
2546 | length += count; | ||
2547 | info->recv_cnt -= count; | 2513 | info->recv_cnt -= count; |
2548 | DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length)); | ||
2549 | 2514 | ||
2550 | if (count == buffer->length) { | 2515 | if (count == buffer->length) { |
2551 | info->first_recv_buffer = buffer->next; | 2516 | info->first_recv_buffer = buffer->next; |
@@ -2560,14 +2525,6 @@ static void flush_to_flip_buffer(struct e100_serial *info) | |||
2560 | if (!info->first_recv_buffer) | 2525 | if (!info->first_recv_buffer) |
2561 | info->last_recv_buffer = NULL; | 2526 | info->last_recv_buffer = NULL; |
2562 | 2527 | ||
2563 | tty->flip.count = length; | ||
2564 | DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) { | ||
2565 | DEBUG_LOG(info->line, "ldisc %lu\n", | ||
2566 | tty->ldisc.chars_in_buffer(tty)); | ||
2567 | DEBUG_LOG(info->line, "flip.count %lu\n", | ||
2568 | tty->flip.count); | ||
2569 | } | ||
2570 | ); | ||
2571 | restore_flags(flags); | 2528 | restore_flags(flags); |
2572 | 2529 | ||
2573 | DFLIP( | 2530 | DFLIP( |
@@ -2722,17 +2679,17 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) | |||
2722 | printk("!NO TTY!\n"); | 2679 | printk("!NO TTY!\n"); |
2723 | return info; | 2680 | return info; |
2724 | } | 2681 | } |
2725 | if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) { | 2682 | if (tty->flip.count >= CRIS_BUF_SIZE - TTY_THRESHOLD_THROTTLE) { |
2726 | /* check TTY_THROTTLED first so it indicates our state */ | 2683 | /* check TTY_THROTTLED first so it indicates our state */ |
2727 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) { | 2684 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) { |
2728 | DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count)); | 2685 | DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count)); |
2729 | rs_throttle(tty); | 2686 | rs_throttle(tty); |
2730 | } | 2687 | } |
2731 | } | 2688 | } |
2732 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) { | 2689 | if (tty->flip.count >= CRIS_BUF_SIZE) { |
2733 | DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count); | 2690 | DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count); |
2734 | tty->flip.work.func((void *) tty); | 2691 | tty->flip.work.func((void *) tty); |
2735 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) { | 2692 | if (tty->flip.count >= CRIS_BUF_SIZE) { |
2736 | DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count); | 2693 | DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count); |
2737 | return info; /* if TTY_DONT_FLIP is set */ | 2694 | return info; /* if TTY_DONT_FLIP is set */ |
2738 | } | 2695 | } |
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 6e09c8b395e8..348ee2c19b58 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c | |||
@@ -539,7 +539,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up) | |||
539 | static int serial_link_irq_chain(struct uart_sio_port *up) | 539 | static int serial_link_irq_chain(struct uart_sio_port *up) |
540 | { | 540 | { |
541 | struct irq_info *i = irq_lists + up->port.irq; | 541 | struct irq_info *i = irq_lists + up->port.irq; |
542 | int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; | 542 | int ret, irq_flags = 0; |
543 | 543 | ||
544 | spin_lock_irq(&i->lock); | 544 | spin_lock_irq(&i->lock); |
545 | 545 | ||
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h index 849f1b2c2531..e9b7e11793b1 100644 --- a/drivers/serial/m32r_sio.h +++ b/drivers/serial/m32r_sio.h | |||
@@ -46,9 +46,3 @@ struct old_serial_port { | |||
46 | #define PROBE_ANY (~0) | 46 | #define PROBE_ANY (~0) |
47 | 47 | ||
48 | #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) | 48 | #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) |
49 | |||
50 | #ifdef CONFIG_SERIAL_SIO_SHARE_IRQ | ||
51 | #define M32R_SIO_SHARE_IRQS 1 | ||
52 | #else | ||
53 | #define M32R_SIO_SHARE_IRQS 0 | ||
54 | #endif | ||
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index a3bd3a3f41f3..68aa4da01865 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -1938,9 +1938,24 @@ static void uart_change_pm(struct uart_state *state, int pm_state) | |||
1938 | } | 1938 | } |
1939 | } | 1939 | } |
1940 | 1940 | ||
1941 | struct uart_match { | ||
1942 | struct uart_port *port; | ||
1943 | struct uart_driver *driver; | ||
1944 | }; | ||
1945 | |||
1946 | static int serial_match_port(struct device *dev, void *data) | ||
1947 | { | ||
1948 | struct uart_match *match = data; | ||
1949 | dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line; | ||
1950 | |||
1951 | return dev->devt == devt; /* Actually, only one tty per port */ | ||
1952 | } | ||
1953 | |||
1941 | int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) | 1954 | int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) |
1942 | { | 1955 | { |
1943 | struct uart_state *state = drv->state + port->line; | 1956 | struct uart_state *state = drv->state + port->line; |
1957 | struct device *tty_dev; | ||
1958 | struct uart_match match = {port, drv}; | ||
1944 | 1959 | ||
1945 | mutex_lock(&state->mutex); | 1960 | mutex_lock(&state->mutex); |
1946 | 1961 | ||
@@ -1951,6 +1966,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) | |||
1951 | } | 1966 | } |
1952 | #endif | 1967 | #endif |
1953 | 1968 | ||
1969 | tty_dev = device_find_child(port->dev, &match, serial_match_port); | ||
1970 | if (device_may_wakeup(tty_dev)) { | ||
1971 | enable_irq_wake(port->irq); | ||
1972 | put_device(tty_dev); | ||
1973 | mutex_unlock(&state->mutex); | ||
1974 | return 0; | ||
1975 | } | ||
1976 | port->suspended = 1; | ||
1977 | |||
1954 | if (state->info && state->info->flags & UIF_INITIALIZED) { | 1978 | if (state->info && state->info->flags & UIF_INITIALIZED) { |
1955 | const struct uart_ops *ops = port->ops; | 1979 | const struct uart_ops *ops = port->ops; |
1956 | 1980 | ||
@@ -1999,6 +2023,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) | |||
1999 | } | 2023 | } |
2000 | #endif | 2024 | #endif |
2001 | 2025 | ||
2026 | if (!port->suspended) { | ||
2027 | disable_irq_wake(port->irq); | ||
2028 | mutex_unlock(&state->mutex); | ||
2029 | return 0; | ||
2030 | } | ||
2031 | port->suspended = 0; | ||
2032 | |||
2002 | uart_change_pm(state, 0); | 2033 | uart_change_pm(state, 0); |
2003 | 2034 | ||
2004 | /* | 2035 | /* |
@@ -2278,6 +2309,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2278 | { | 2309 | { |
2279 | struct uart_state *state; | 2310 | struct uart_state *state; |
2280 | int ret = 0; | 2311 | int ret = 0; |
2312 | struct device *tty_dev; | ||
2281 | 2313 | ||
2282 | BUG_ON(in_interrupt()); | 2314 | BUG_ON(in_interrupt()); |
2283 | 2315 | ||
@@ -2314,7 +2346,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2314 | * Register the port whether it's detected or not. This allows | 2346 | * Register the port whether it's detected or not. This allows |
2315 | * setserial to be used to alter this ports parameters. | 2347 | * setserial to be used to alter this ports parameters. |
2316 | */ | 2348 | */ |
2317 | tty_register_device(drv->tty_driver, port->line, port->dev); | 2349 | tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev); |
2350 | if (likely(!IS_ERR(tty_dev))) { | ||
2351 | device_can_wakeup(tty_dev) = 1; | ||
2352 | device_set_wakeup_enable(tty_dev, 0); | ||
2353 | } else | ||
2354 | printk(KERN_ERR "Cannot register tty device on line %d\n", | ||
2355 | port->line); | ||
2318 | 2356 | ||
2319 | /* | 2357 | /* |
2320 | * Ensure UPF_DEAD is not set. | 2358 | * Ensure UPF_DEAD is not set. |
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7c8d78fbbbfb..5afcb2fa7cd3 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -911,6 +911,7 @@ static struct pcmcia_device_id serial_ids[] = { | |||
911 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), | 911 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), |
912 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), | 912 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), |
913 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), | 913 | PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), |
914 | PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ | ||
914 | PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ | 915 | PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ |
915 | PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ | 916 | PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ |
916 | PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ | 917 | PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ |
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 0930e2a85514..6846a6c38b6d 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c | |||
@@ -25,19 +25,15 @@ | |||
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
28 | #include <linux/sysrq.h> | ||
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
31 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
32 | #include <linux/tty.h> | ||
33 | #include <linux/tty_flip.h> | ||
34 | #include <linux/serial_core.h> | 31 | #include <linux/serial_core.h> |
35 | #include <linux/serial.h> | 32 | #include <linux/serial.h> |
36 | #include <linux/mutex.h> | ||
37 | 33 | ||
38 | #include <asm/io.h> | 34 | #include <asm/io.h> |
39 | 35 | ||
40 | static char *serial_version = "1.10"; | 36 | static char *serial_version = "1.11"; |
41 | static char *serial_name = "TX39/49 Serial driver"; | 37 | static char *serial_name = "TX39/49 Serial driver"; |
42 | 38 | ||
43 | #define PASS_LIMIT 256 | 39 | #define PASS_LIMIT 256 |
@@ -68,8 +64,6 @@ static char *serial_name = "TX39/49 Serial driver"; | |||
68 | */ | 64 | */ |
69 | #define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS | 65 | #define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS |
70 | 66 | ||
71 | #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) | ||
72 | |||
73 | struct uart_txx9_port { | 67 | struct uart_txx9_port { |
74 | struct uart_port port; | 68 | struct uart_port port; |
75 | /* No additional info for now */ | 69 | /* No additional info for now */ |
@@ -756,21 +750,6 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) | |||
756 | serial_txx9_initialize(port); | 750 | serial_txx9_initialize(port); |
757 | } | 751 | } |
758 | 752 | ||
759 | static int | ||
760 | serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
761 | { | ||
762 | unsigned long new_port = ser->port; | ||
763 | if (HIGH_BITS_OFFSET) | ||
764 | new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET; | ||
765 | if (ser->type != port->type || | ||
766 | ser->irq != port->irq || | ||
767 | ser->io_type != port->iotype || | ||
768 | new_port != port->iobase || | ||
769 | (unsigned long)ser->iomem_base != port->mapbase) | ||
770 | return -EINVAL; | ||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static const char * | 753 | static const char * |
775 | serial_txx9_type(struct uart_port *port) | 754 | serial_txx9_type(struct uart_port *port) |
776 | { | 755 | { |
@@ -794,7 +773,6 @@ static struct uart_ops serial_txx9_pops = { | |||
794 | .release_port = serial_txx9_release_port, | 773 | .release_port = serial_txx9_release_port, |
795 | .request_port = serial_txx9_request_port, | 774 | .request_port = serial_txx9_request_port, |
796 | .config_port = serial_txx9_config_port, | 775 | .config_port = serial_txx9_config_port, |
797 | .verify_port = serial_txx9_verify_port, | ||
798 | }; | 776 | }; |
799 | 777 | ||
800 | static struct uart_txx9_port serial_txx9_ports[UART_NR]; | 778 | static struct uart_txx9_port serial_txx9_ports[UART_NR]; |
@@ -950,7 +928,8 @@ int __init early_serial_txx9_setup(struct uart_port *port) | |||
950 | 928 | ||
951 | serial_txx9_ports[port->line].port = *port; | 929 | serial_txx9_ports[port->line].port = *port; |
952 | serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; | 930 | serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; |
953 | serial_txx9_ports[port->line].port.flags |= UPF_BOOT_AUTOCONF; | 931 | serial_txx9_ports[port->line].port.flags |= |
932 | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; | ||
954 | return 0; | 933 | return 0; |
955 | } | 934 | } |
956 | 935 | ||
@@ -995,7 +974,8 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) | |||
995 | uart->port.irq = port->irq; | 974 | uart->port.irq = port->irq; |
996 | uart->port.uartclk = port->uartclk; | 975 | uart->port.uartclk = port->uartclk; |
997 | uart->port.iotype = port->iotype; | 976 | uart->port.iotype = port->iotype; |
998 | uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; | 977 | uart->port.flags = port->flags |
978 | | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; | ||
999 | uart->port.mapbase = port->mapbase; | 979 | uart->port.mapbase = port->mapbase; |
1000 | if (port->dev) | 980 | if (port->dev) |
1001 | uart->port.dev = port->dev; | 981 | uart->port.dev = port->dev; |
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b91571122daa..a77ede598d34 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -124,16 +124,17 @@ config SPI_MPC52xx_PSC | |||
124 | Controller in master SPI mode. | 124 | Controller in master SPI mode. |
125 | 125 | ||
126 | config SPI_MPC83xx | 126 | config SPI_MPC83xx |
127 | tristate "Freescale MPC83xx SPI controller" | 127 | tristate "Freescale MPC83xx/QUICC Engine SPI controller" |
128 | depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL | 128 | depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL |
129 | select SPI_BITBANG | 129 | select SPI_BITBANG |
130 | help | 130 | help |
131 | This enables using the Freescale MPC83xx SPI controller in master | 131 | This enables using the Freescale MPC83xx and QUICC Engine SPI |
132 | mode. | 132 | controllers in master mode. |
133 | 133 | ||
134 | Note, this driver uniquely supports the SPI controller on the MPC83xx | 134 | Note, this driver uniquely supports the SPI controller on the MPC83xx |
135 | family of PowerPC processors. The MPC83xx uses a simple set of shift | 135 | family of PowerPC processors, plus processors with QUICC Engine |
136 | registers for data (opposed to the CPM based descriptor model). | 136 | technology. This driver uses a simple set of shift registers for data |
137 | (opposed to the CPM based descriptor model). | ||
137 | 138 | ||
138 | config SPI_OMAP_UWIRE | 139 | config SPI_OMAP_UWIRE |
139 | tristate "OMAP1 MicroWire" | 140 | tristate "OMAP1 MicroWire" |
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index b0469749310a..0d342dcdd302 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c | |||
@@ -211,7 +211,7 @@ static void atmel_spi_next_message(struct spi_master *master) | |||
211 | msg = list_entry(as->queue.next, struct spi_message, queue); | 211 | msg = list_entry(as->queue.next, struct spi_message, queue); |
212 | spi = msg->spi; | 212 | spi = msg->spi; |
213 | 213 | ||
214 | dev_dbg(master->cdev.dev, "start message %p for %s\n", | 214 | dev_dbg(master->dev.parent, "start message %p for %s\n", |
215 | msg, spi->dev.bus_id); | 215 | msg, spi->dev.bus_id); |
216 | 216 | ||
217 | /* select chip if it's not still active */ | 217 | /* select chip if it's not still active */ |
@@ -266,10 +266,10 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master, | |||
266 | struct spi_transfer *xfer) | 266 | struct spi_transfer *xfer) |
267 | { | 267 | { |
268 | if (xfer->tx_dma != INVALID_DMA_ADDRESS) | 268 | if (xfer->tx_dma != INVALID_DMA_ADDRESS) |
269 | dma_unmap_single(master->cdev.dev, xfer->tx_dma, | 269 | dma_unmap_single(master->dev.parent, xfer->tx_dma, |
270 | xfer->len, DMA_TO_DEVICE); | 270 | xfer->len, DMA_TO_DEVICE); |
271 | if (xfer->rx_dma != INVALID_DMA_ADDRESS) | 271 | if (xfer->rx_dma != INVALID_DMA_ADDRESS) |
272 | dma_unmap_single(master->cdev.dev, xfer->rx_dma, | 272 | dma_unmap_single(master->dev.parent, xfer->rx_dma, |
273 | xfer->len, DMA_FROM_DEVICE); | 273 | xfer->len, DMA_FROM_DEVICE); |
274 | } | 274 | } |
275 | 275 | ||
@@ -285,7 +285,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, | |||
285 | list_del(&msg->queue); | 285 | list_del(&msg->queue); |
286 | msg->status = status; | 286 | msg->status = status; |
287 | 287 | ||
288 | dev_dbg(master->cdev.dev, | 288 | dev_dbg(master->dev.parent, |
289 | "xfer complete: %u bytes transferred\n", | 289 | "xfer complete: %u bytes transferred\n", |
290 | msg->actual_length); | 290 | msg->actual_length); |
291 | 291 | ||
@@ -348,7 +348,7 @@ atmel_spi_interrupt(int irq, void *dev_id) | |||
348 | if (xfer->delay_usecs) | 348 | if (xfer->delay_usecs) |
349 | udelay(xfer->delay_usecs); | 349 | udelay(xfer->delay_usecs); |
350 | 350 | ||
351 | dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n", | 351 | dev_warn(master->dev.parent, "fifo overrun (%u/%u remaining)\n", |
352 | spi_readl(as, TCR), spi_readl(as, RCR)); | 352 | spi_readl(as, TCR), spi_readl(as, RCR)); |
353 | 353 | ||
354 | /* | 354 | /* |
@@ -363,7 +363,7 @@ atmel_spi_interrupt(int irq, void *dev_id) | |||
363 | if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) | 363 | if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) |
364 | break; | 364 | break; |
365 | if (!timeout) | 365 | if (!timeout) |
366 | dev_warn(master->cdev.dev, | 366 | dev_warn(master->dev.parent, |
367 | "timeout waiting for TXEMPTY"); | 367 | "timeout waiting for TXEMPTY"); |
368 | while (spi_readl(as, SR) & SPI_BIT(RDRF)) | 368 | while (spi_readl(as, SR) & SPI_BIT(RDRF)) |
369 | spi_readl(as, RDR); | 369 | spi_readl(as, RDR); |
@@ -526,7 +526,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) | |||
526 | struct atmel_spi *as; | 526 | struct atmel_spi *as; |
527 | struct spi_transfer *xfer; | 527 | struct spi_transfer *xfer; |
528 | unsigned long flags; | 528 | unsigned long flags; |
529 | struct device *controller = spi->master->cdev.dev; | 529 | struct device *controller = spi->master->dev.parent; |
530 | 530 | ||
531 | as = spi_master_get_devdata(spi->master); | 531 | as = spi_master_get_devdata(spi->master); |
532 | 532 | ||
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index d2a4b2bdb07b..e9aba932f217 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c | |||
@@ -503,7 +503,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, | |||
503 | INIT_LIST_HEAD(&mps->queue); | 503 | INIT_LIST_HEAD(&mps->queue); |
504 | 504 | ||
505 | mps->workqueue = create_singlethread_workqueue( | 505 | mps->workqueue = create_singlethread_workqueue( |
506 | master->cdev.dev->bus_id); | 506 | master->dev.parent->bus_id); |
507 | if (mps->workqueue == NULL) { | 507 | if (mps->workqueue == NULL) { |
508 | ret = -EBUSY; | 508 | ret = -EBUSY; |
509 | goto free_irq; | 509 | goto free_irq; |
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 6b357cdb9ea3..3cdab131c4a9 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c | |||
@@ -645,7 +645,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) | |||
645 | 645 | ||
646 | clk_enable(mcspi->ick); | 646 | clk_enable(mcspi->ick); |
647 | clk_enable(mcspi->fck); | 647 | clk_enable(mcspi->fck); |
648 | ret = omap2_mcspi_setup_transfer(spi, NULL); | 648 | ret = omap2_mcspi_setup_transfer(spi, NULL); |
649 | clk_disable(mcspi->fck); | 649 | clk_disable(mcspi->fck); |
650 | clk_disable(mcspi->ick); | 650 | clk_disable(mcspi->ick); |
651 | 651 | ||
@@ -693,7 +693,6 @@ static void omap2_mcspi_work(struct work_struct *work) | |||
693 | struct spi_device *spi; | 693 | struct spi_device *spi; |
694 | struct spi_transfer *t = NULL; | 694 | struct spi_transfer *t = NULL; |
695 | int cs_active = 0; | 695 | int cs_active = 0; |
696 | struct omap2_mcspi_device_config *conf; | ||
697 | struct omap2_mcspi_cs *cs; | 696 | struct omap2_mcspi_cs *cs; |
698 | int par_override = 0; | 697 | int par_override = 0; |
699 | int status = 0; | 698 | int status = 0; |
@@ -706,7 +705,6 @@ static void omap2_mcspi_work(struct work_struct *work) | |||
706 | spin_unlock_irq(&mcspi->lock); | 705 | spin_unlock_irq(&mcspi->lock); |
707 | 706 | ||
708 | spi = m->spi; | 707 | spi = m->spi; |
709 | conf = spi->controller_data; | ||
710 | cs = spi->controller_state; | 708 | cs = spi->controller_state; |
711 | 709 | ||
712 | omap2_mcspi_set_enable(spi, 1); | 710 | omap2_mcspi_set_enable(spi, 1); |
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index d275c615a73e..8245b5153f30 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c | |||
@@ -481,7 +481,7 @@ static void uwire_off(struct uwire_spi *uwire) | |||
481 | spi_master_put(uwire->bitbang.master); | 481 | spi_master_put(uwire->bitbang.master); |
482 | } | 482 | } |
483 | 483 | ||
484 | static int uwire_probe(struct platform_device *pdev) | 484 | static int __init uwire_probe(struct platform_device *pdev) |
485 | { | 485 | { |
486 | struct spi_master *master; | 486 | struct spi_master *master; |
487 | struct uwire_spi *uwire; | 487 | struct uwire_spi *uwire; |
@@ -525,7 +525,7 @@ static int uwire_probe(struct platform_device *pdev) | |||
525 | return status; | 525 | return status; |
526 | } | 526 | } |
527 | 527 | ||
528 | static int uwire_remove(struct platform_device *pdev) | 528 | static int __exit uwire_remove(struct platform_device *pdev) |
529 | { | 529 | { |
530 | struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev); | 530 | struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev); |
531 | int status; | 531 | int status; |
@@ -543,8 +543,7 @@ static struct platform_driver uwire_driver = { | |||
543 | .bus = &platform_bus_type, | 543 | .bus = &platform_bus_type, |
544 | .owner = THIS_MODULE, | 544 | .owner = THIS_MODULE, |
545 | }, | 545 | }, |
546 | .probe = uwire_probe, | 546 | .remove = __exit_p(uwire_remove), |
547 | .remove = uwire_remove, | ||
548 | // suspend ... unuse ck | 547 | // suspend ... unuse ck |
549 | // resume ... use ck | 548 | // resume ... use ck |
550 | }; | 549 | }; |
@@ -566,7 +565,7 @@ static int __init omap_uwire_init(void) | |||
566 | omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9); | 565 | omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9); |
567 | } | 566 | } |
568 | 567 | ||
569 | return platform_driver_register(&uwire_driver); | 568 | return platform_driver_probe(&uwire_driver, uwire_probe); |
570 | } | 569 | } |
571 | 570 | ||
572 | static void __exit omap_uwire_exit(void) | 571 | static void __exit omap_uwire_exit(void) |
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index e51311b2da0b..5f3d808cbc29 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
27 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/errno.h> | ||
30 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
31 | 30 | ||
32 | #include <asm/io.h> | 31 | #include <asm/io.h> |
@@ -1230,7 +1229,7 @@ static void cleanup(struct spi_device *spi) | |||
1230 | kfree(chip); | 1229 | kfree(chip); |
1231 | } | 1230 | } |
1232 | 1231 | ||
1233 | static int init_queue(struct driver_data *drv_data) | 1232 | static int __init init_queue(struct driver_data *drv_data) |
1234 | { | 1233 | { |
1235 | INIT_LIST_HEAD(&drv_data->queue); | 1234 | INIT_LIST_HEAD(&drv_data->queue); |
1236 | spin_lock_init(&drv_data->lock); | 1235 | spin_lock_init(&drv_data->lock); |
@@ -1243,7 +1242,7 @@ static int init_queue(struct driver_data *drv_data) | |||
1243 | 1242 | ||
1244 | INIT_WORK(&drv_data->pump_messages, pump_messages); | 1243 | INIT_WORK(&drv_data->pump_messages, pump_messages); |
1245 | drv_data->workqueue = create_singlethread_workqueue( | 1244 | drv_data->workqueue = create_singlethread_workqueue( |
1246 | drv_data->master->cdev.dev->bus_id); | 1245 | drv_data->master->dev.parent->bus_id); |
1247 | if (drv_data->workqueue == NULL) | 1246 | if (drv_data->workqueue == NULL) |
1248 | return -EBUSY; | 1247 | return -EBUSY; |
1249 | 1248 | ||
@@ -1318,7 +1317,7 @@ static int destroy_queue(struct driver_data *drv_data) | |||
1318 | return 0; | 1317 | return 0; |
1319 | } | 1318 | } |
1320 | 1319 | ||
1321 | static int pxa2xx_spi_probe(struct platform_device *pdev) | 1320 | static int __init pxa2xx_spi_probe(struct platform_device *pdev) |
1322 | { | 1321 | { |
1323 | struct device *dev = &pdev->dev; | 1322 | struct device *dev = &pdev->dev; |
1324 | struct pxa2xx_spi_master *platform_info; | 1323 | struct pxa2xx_spi_master *platform_info; |
@@ -1622,8 +1621,7 @@ static struct platform_driver driver = { | |||
1622 | .bus = &platform_bus_type, | 1621 | .bus = &platform_bus_type, |
1623 | .owner = THIS_MODULE, | 1622 | .owner = THIS_MODULE, |
1624 | }, | 1623 | }, |
1625 | .probe = pxa2xx_spi_probe, | 1624 | .remove = pxa2xx_spi_remove, |
1626 | .remove = __devexit_p(pxa2xx_spi_remove), | ||
1627 | .shutdown = pxa2xx_spi_shutdown, | 1625 | .shutdown = pxa2xx_spi_shutdown, |
1628 | .suspend = pxa2xx_spi_suspend, | 1626 | .suspend = pxa2xx_spi_suspend, |
1629 | .resume = pxa2xx_spi_resume, | 1627 | .resume = pxa2xx_spi_resume, |
@@ -1631,9 +1629,7 @@ static struct platform_driver driver = { | |||
1631 | 1629 | ||
1632 | static int __init pxa2xx_spi_init(void) | 1630 | static int __init pxa2xx_spi_init(void) |
1633 | { | 1631 | { |
1634 | platform_driver_register(&driver); | 1632 | return platform_driver_probe(&driver, pxa2xx_spi_probe); |
1635 | |||
1636 | return 0; | ||
1637 | } | 1633 | } |
1638 | module_init(pxa2xx_spi_init); | 1634 | module_init(pxa2xx_spi_init); |
1639 | 1635 | ||
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bcb8dd5fb0b4..89769ce16f88 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -204,7 +204,7 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
204 | struct spi_board_info *chip) | 204 | struct spi_board_info *chip) |
205 | { | 205 | { |
206 | struct spi_device *proxy; | 206 | struct spi_device *proxy; |
207 | struct device *dev = master->cdev.dev; | 207 | struct device *dev = master->dev.parent; |
208 | int status; | 208 | int status; |
209 | 209 | ||
210 | /* NOTE: caller did any chip->bus_num checks necessary. | 210 | /* NOTE: caller did any chip->bus_num checks necessary. |
@@ -239,7 +239,7 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
239 | proxy->modalias = chip->modalias; | 239 | proxy->modalias = chip->modalias; |
240 | 240 | ||
241 | snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, | 241 | snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, |
242 | "%s.%u", master->cdev.class_id, | 242 | "%s.%u", master->dev.bus_id, |
243 | chip->chip_select); | 243 | chip->chip_select); |
244 | proxy->dev.parent = dev; | 244 | proxy->dev.parent = dev; |
245 | proxy->dev.bus = &spi_bus_type; | 245 | proxy->dev.bus = &spi_bus_type; |
@@ -338,18 +338,18 @@ static void scan_boardinfo(struct spi_master *master) | |||
338 | 338 | ||
339 | /*-------------------------------------------------------------------------*/ | 339 | /*-------------------------------------------------------------------------*/ |
340 | 340 | ||
341 | static void spi_master_release(struct class_device *cdev) | 341 | static void spi_master_release(struct device *dev) |
342 | { | 342 | { |
343 | struct spi_master *master; | 343 | struct spi_master *master; |
344 | 344 | ||
345 | master = container_of(cdev, struct spi_master, cdev); | 345 | master = container_of(dev, struct spi_master, dev); |
346 | kfree(master); | 346 | kfree(master); |
347 | } | 347 | } |
348 | 348 | ||
349 | static struct class spi_master_class = { | 349 | static struct class spi_master_class = { |
350 | .name = "spi_master", | 350 | .name = "spi_master", |
351 | .owner = THIS_MODULE, | 351 | .owner = THIS_MODULE, |
352 | .release = spi_master_release, | 352 | .dev_release = spi_master_release, |
353 | }; | 353 | }; |
354 | 354 | ||
355 | 355 | ||
@@ -357,7 +357,7 @@ static struct class spi_master_class = { | |||
357 | * spi_alloc_master - allocate SPI master controller | 357 | * spi_alloc_master - allocate SPI master controller |
358 | * @dev: the controller, possibly using the platform_bus | 358 | * @dev: the controller, possibly using the platform_bus |
359 | * @size: how much zeroed driver-private data to allocate; the pointer to this | 359 | * @size: how much zeroed driver-private data to allocate; the pointer to this |
360 | * memory is in the class_data field of the returned class_device, | 360 | * memory is in the driver_data field of the returned device, |
361 | * accessible with spi_master_get_devdata(). | 361 | * accessible with spi_master_get_devdata(). |
362 | * Context: can sleep | 362 | * Context: can sleep |
363 | * | 363 | * |
@@ -383,9 +383,9 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) | |||
383 | if (!master) | 383 | if (!master) |
384 | return NULL; | 384 | return NULL; |
385 | 385 | ||
386 | class_device_initialize(&master->cdev); | 386 | device_initialize(&master->dev); |
387 | master->cdev.class = &spi_master_class; | 387 | master->dev.class = &spi_master_class; |
388 | master->cdev.dev = get_device(dev); | 388 | master->dev.parent = get_device(dev); |
389 | spi_master_set_devdata(master, &master[1]); | 389 | spi_master_set_devdata(master, &master[1]); |
390 | 390 | ||
391 | return master; | 391 | return master; |
@@ -415,7 +415,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master); | |||
415 | int spi_register_master(struct spi_master *master) | 415 | int spi_register_master(struct spi_master *master) |
416 | { | 416 | { |
417 | static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); | 417 | static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); |
418 | struct device *dev = master->cdev.dev; | 418 | struct device *dev = master->dev.parent; |
419 | int status = -ENODEV; | 419 | int status = -ENODEV; |
420 | int dynamic = 0; | 420 | int dynamic = 0; |
421 | 421 | ||
@@ -440,12 +440,12 @@ int spi_register_master(struct spi_master *master) | |||
440 | /* register the device, then userspace will see it. | 440 | /* register the device, then userspace will see it. |
441 | * registration fails if the bus ID is in use. | 441 | * registration fails if the bus ID is in use. |
442 | */ | 442 | */ |
443 | snprintf(master->cdev.class_id, sizeof master->cdev.class_id, | 443 | snprintf(master->dev.bus_id, sizeof master->dev.bus_id, |
444 | "spi%u", master->bus_num); | 444 | "spi%u", master->bus_num); |
445 | status = class_device_add(&master->cdev); | 445 | status = device_add(&master->dev); |
446 | if (status < 0) | 446 | if (status < 0) |
447 | goto done; | 447 | goto done; |
448 | dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, | 448 | dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id, |
449 | dynamic ? " (dynamic)" : ""); | 449 | dynamic ? " (dynamic)" : ""); |
450 | 450 | ||
451 | /* populate children from any spi device tables */ | 451 | /* populate children from any spi device tables */ |
@@ -478,8 +478,8 @@ void spi_unregister_master(struct spi_master *master) | |||
478 | { | 478 | { |
479 | int dummy; | 479 | int dummy; |
480 | 480 | ||
481 | dummy = device_for_each_child(master->cdev.dev, NULL, __unregister); | 481 | dummy = device_for_each_child(master->dev.parent, NULL, __unregister); |
482 | class_device_unregister(&master->cdev); | 482 | device_unregister(&master->dev); |
483 | } | 483 | } |
484 | EXPORT_SYMBOL_GPL(spi_unregister_master); | 484 | EXPORT_SYMBOL_GPL(spi_unregister_master); |
485 | 485 | ||
@@ -495,13 +495,13 @@ EXPORT_SYMBOL_GPL(spi_unregister_master); | |||
495 | */ | 495 | */ |
496 | struct spi_master *spi_busnum_to_master(u16 bus_num) | 496 | struct spi_master *spi_busnum_to_master(u16 bus_num) |
497 | { | 497 | { |
498 | struct class_device *cdev; | 498 | struct device *dev; |
499 | struct spi_master *master = NULL; | 499 | struct spi_master *master = NULL; |
500 | struct spi_master *m; | 500 | struct spi_master *m; |
501 | 501 | ||
502 | down(&spi_master_class.sem); | 502 | down(&spi_master_class.sem); |
503 | list_for_each_entry(cdev, &spi_master_class.children, node) { | 503 | list_for_each_entry(dev, &spi_master_class.children, node) { |
504 | m = container_of(cdev, struct spi_master, cdev); | 504 | m = container_of(dev, struct spi_master, dev); |
505 | if (m->bus_num == bus_num) { | 505 | if (m->bus_num == bus_num) { |
506 | master = spi_master_get(m); | 506 | master = spi_master_get(m); |
507 | break; | 507 | break; |
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f540ed77a102..6cb71d74738f 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <linux/dma-mapping.h> | 39 | #include <linux/dma-mapping.h> |
40 | #include <linux/spi/spi.h> | 40 | #include <linux/spi/spi.h> |
41 | #include <linux/workqueue.h> | 41 | #include <linux/workqueue.h> |
42 | #include <linux/errno.h> | ||
43 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
44 | 43 | ||
45 | #include <asm/io.h> | 44 | #include <asm/io.h> |
@@ -1107,7 +1106,7 @@ static inline int init_queue(struct driver_data *drv_data) | |||
1107 | /* init messages workqueue */ | 1106 | /* init messages workqueue */ |
1108 | INIT_WORK(&drv_data->pump_messages, pump_messages); | 1107 | INIT_WORK(&drv_data->pump_messages, pump_messages); |
1109 | drv_data->workqueue = | 1108 | drv_data->workqueue = |
1110 | create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id); | 1109 | create_singlethread_workqueue(drv_data->master->dev.parent->bus_id); |
1111 | if (drv_data->workqueue == NULL) | 1110 | if (drv_data->workqueue == NULL) |
1112 | return -EBUSY; | 1111 | return -EBUSY; |
1113 | 1112 | ||
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 0c85c984ccb4..81639c6be1c7 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c | |||
@@ -472,7 +472,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) | |||
472 | /* this task is the only thing to touch the SPI bits */ | 472 | /* this task is the only thing to touch the SPI bits */ |
473 | bitbang->busy = 0; | 473 | bitbang->busy = 0; |
474 | bitbang->workqueue = create_singlethread_workqueue( | 474 | bitbang->workqueue = create_singlethread_workqueue( |
475 | bitbang->master->cdev.dev->bus_id); | 475 | bitbang->master->dev.parent->bus_id); |
476 | if (bitbang->workqueue == NULL) { | 476 | if (bitbang->workqueue == NULL) { |
477 | status = -EBUSY; | 477 | status = -EBUSY; |
478 | goto err1; | 478 | goto err1; |
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index bd9177f51de9..3b4650ae6f1a 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c | |||
@@ -1361,7 +1361,7 @@ static void cleanup(struct spi_device *spi) | |||
1361 | kfree(spi_get_ctldata(spi)); | 1361 | kfree(spi_get_ctldata(spi)); |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | static int init_queue(struct driver_data *drv_data) | 1364 | static int __init init_queue(struct driver_data *drv_data) |
1365 | { | 1365 | { |
1366 | INIT_LIST_HEAD(&drv_data->queue); | 1366 | INIT_LIST_HEAD(&drv_data->queue); |
1367 | spin_lock_init(&drv_data->lock); | 1367 | spin_lock_init(&drv_data->lock); |
@@ -1374,7 +1374,7 @@ static int init_queue(struct driver_data *drv_data) | |||
1374 | 1374 | ||
1375 | INIT_WORK(&drv_data->work, pump_messages); | 1375 | INIT_WORK(&drv_data->work, pump_messages); |
1376 | drv_data->workqueue = create_singlethread_workqueue( | 1376 | drv_data->workqueue = create_singlethread_workqueue( |
1377 | drv_data->master->cdev.dev->bus_id); | 1377 | drv_data->master->dev.parent->bus_id); |
1378 | if (drv_data->workqueue == NULL) | 1378 | if (drv_data->workqueue == NULL) |
1379 | return -EBUSY; | 1379 | return -EBUSY; |
1380 | 1380 | ||
@@ -1444,7 +1444,7 @@ static int destroy_queue(struct driver_data *drv_data) | |||
1444 | return 0; | 1444 | return 0; |
1445 | } | 1445 | } |
1446 | 1446 | ||
1447 | static int spi_imx_probe(struct platform_device *pdev) | 1447 | static int __init spi_imx_probe(struct platform_device *pdev) |
1448 | { | 1448 | { |
1449 | struct device *dev = &pdev->dev; | 1449 | struct device *dev = &pdev->dev; |
1450 | struct spi_imx_master *platform_info; | 1450 | struct spi_imx_master *platform_info; |
@@ -1622,7 +1622,7 @@ err_no_mem: | |||
1622 | return status; | 1622 | return status; |
1623 | } | 1623 | } |
1624 | 1624 | ||
1625 | static int __devexit spi_imx_remove(struct platform_device *pdev) | 1625 | static int __exit spi_imx_remove(struct platform_device *pdev) |
1626 | { | 1626 | { |
1627 | struct driver_data *drv_data = platform_get_drvdata(pdev); | 1627 | struct driver_data *drv_data = platform_get_drvdata(pdev); |
1628 | int irq; | 1628 | int irq; |
@@ -1739,8 +1739,7 @@ static struct platform_driver driver = { | |||
1739 | .bus = &platform_bus_type, | 1739 | .bus = &platform_bus_type, |
1740 | .owner = THIS_MODULE, | 1740 | .owner = THIS_MODULE, |
1741 | }, | 1741 | }, |
1742 | .probe = spi_imx_probe, | 1742 | .remove = __exit_p(spi_imx_remove), |
1743 | .remove = __devexit_p(spi_imx_remove), | ||
1744 | .shutdown = spi_imx_shutdown, | 1743 | .shutdown = spi_imx_shutdown, |
1745 | .suspend = spi_imx_suspend, | 1744 | .suspend = spi_imx_suspend, |
1746 | .resume = spi_imx_resume, | 1745 | .resume = spi_imx_resume, |
@@ -1748,7 +1747,7 @@ static struct platform_driver driver = { | |||
1748 | 1747 | ||
1749 | static int __init spi_imx_init(void) | 1748 | static int __init spi_imx_init(void) |
1750 | { | 1749 | { |
1751 | return platform_driver_register(&driver); | 1750 | return platform_driver_probe(&driver, spi_imx_probe); |
1752 | } | 1751 | } |
1753 | module_init(spi_imx_init); | 1752 | module_init(spi_imx_init); |
1754 | 1753 | ||
diff --git a/drivers/spi/spi_lm70llp.c b/drivers/spi/spi_lm70llp.c index 4ea68ac16115..39d8d8ad65c0 100644 --- a/drivers/spi/spi_lm70llp.c +++ b/drivers/spi/spi_lm70llp.c | |||
@@ -82,7 +82,7 @@ struct spi_lm70llp { | |||
82 | struct pardevice *pd; | 82 | struct pardevice *pd; |
83 | struct spi_device *spidev_lm70; | 83 | struct spi_device *spidev_lm70; |
84 | struct spi_board_info info; | 84 | struct spi_board_info info; |
85 | struct class_device *cdev; | 85 | //struct device *dev; |
86 | }; | 86 | }; |
87 | 87 | ||
88 | /* REVISIT : ugly global ; provides "exclusive open" facility */ | 88 | /* REVISIT : ugly global ; provides "exclusive open" facility */ |
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index 32cda77b31cd..4580b9cf625d 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c | |||
@@ -511,7 +511,7 @@ err: | |||
511 | return ret; | 511 | return ret; |
512 | } | 512 | } |
513 | 513 | ||
514 | static int __devexit mpc83xx_spi_remove(struct platform_device *dev) | 514 | static int __exit mpc83xx_spi_remove(struct platform_device *dev) |
515 | { | 515 | { |
516 | struct mpc83xx_spi *mpc83xx_spi; | 516 | struct mpc83xx_spi *mpc83xx_spi; |
517 | struct spi_master *master; | 517 | struct spi_master *master; |
@@ -529,8 +529,7 @@ static int __devexit mpc83xx_spi_remove(struct platform_device *dev) | |||
529 | 529 | ||
530 | MODULE_ALIAS("mpc83xx_spi"); /* for platform bus hotplug */ | 530 | MODULE_ALIAS("mpc83xx_spi"); /* for platform bus hotplug */ |
531 | static struct platform_driver mpc83xx_spi_driver = { | 531 | static struct platform_driver mpc83xx_spi_driver = { |
532 | .probe = mpc83xx_spi_probe, | 532 | .remove = __exit_p(mpc83xx_spi_remove), |
533 | .remove = __devexit_p(mpc83xx_spi_remove), | ||
534 | .driver = { | 533 | .driver = { |
535 | .name = "mpc83xx_spi", | 534 | .name = "mpc83xx_spi", |
536 | }, | 535 | }, |
@@ -538,7 +537,7 @@ static struct platform_driver mpc83xx_spi_driver = { | |||
538 | 537 | ||
539 | static int __init mpc83xx_spi_init(void) | 538 | static int __init mpc83xx_spi_init(void) |
540 | { | 539 | { |
541 | return platform_driver_register(&mpc83xx_spi_driver); | 540 | return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe); |
542 | } | 541 | } |
543 | 542 | ||
544 | static void __exit mpc83xx_spi_exit(void) | 543 | static void __exit mpc83xx_spi_exit(void) |
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index e9b683f7d7b3..89d6685a5ca4 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c | |||
@@ -233,7 +233,7 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) | |||
233 | return IRQ_HANDLED; | 233 | return IRQ_HANDLED; |
234 | } | 234 | } |
235 | 235 | ||
236 | static int s3c24xx_spi_probe(struct platform_device *pdev) | 236 | static int __init s3c24xx_spi_probe(struct platform_device *pdev) |
237 | { | 237 | { |
238 | struct s3c24xx_spi *hw; | 238 | struct s3c24xx_spi *hw; |
239 | struct spi_master *master; | 239 | struct spi_master *master; |
@@ -382,7 +382,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) | |||
382 | return err; | 382 | return err; |
383 | } | 383 | } |
384 | 384 | ||
385 | static int s3c24xx_spi_remove(struct platform_device *dev) | 385 | static int __exit s3c24xx_spi_remove(struct platform_device *dev) |
386 | { | 386 | { |
387 | struct s3c24xx_spi *hw = platform_get_drvdata(dev); | 387 | struct s3c24xx_spi *hw = platform_get_drvdata(dev); |
388 | 388 | ||
@@ -429,8 +429,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev) | |||
429 | 429 | ||
430 | MODULE_ALIAS("s3c2410_spi"); /* for platform bus hotplug */ | 430 | MODULE_ALIAS("s3c2410_spi"); /* for platform bus hotplug */ |
431 | static struct platform_driver s3c24xx_spidrv = { | 431 | static struct platform_driver s3c24xx_spidrv = { |
432 | .probe = s3c24xx_spi_probe, | 432 | .remove = __exit_p(s3c24xx_spi_remove), |
433 | .remove = s3c24xx_spi_remove, | ||
434 | .suspend = s3c24xx_spi_suspend, | 433 | .suspend = s3c24xx_spi_suspend, |
435 | .resume = s3c24xx_spi_resume, | 434 | .resume = s3c24xx_spi_resume, |
436 | .driver = { | 435 | .driver = { |
@@ -441,7 +440,7 @@ static struct platform_driver s3c24xx_spidrv = { | |||
441 | 440 | ||
442 | static int __init s3c24xx_spi_init(void) | 441 | static int __init s3c24xx_spi_init(void) |
443 | { | 442 | { |
444 | return platform_driver_register(&s3c24xx_spidrv); | 443 | return platform_driver_probe(&s3c24xx_spidrv, s3c24xx_spi_probe); |
445 | } | 444 | } |
446 | 445 | ||
447 | static void __exit s3c24xx_spi_exit(void) | 446 | static void __exit s3c24xx_spi_exit(void) |
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c index b7f4bb239eaf..cc5094f37dd3 100644 --- a/drivers/spi/spi_txx9.c +++ b/drivers/spi/spi_txx9.c | |||
@@ -400,7 +400,7 @@ static int __init txx9spi_probe(struct platform_device *dev) | |||
400 | goto exit; | 400 | goto exit; |
401 | } | 401 | } |
402 | 402 | ||
403 | c->workqueue = create_singlethread_workqueue(master->cdev.dev->bus_id); | 403 | c->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id); |
404 | if (!c->workqueue) | 404 | if (!c->workqueue) |
405 | goto exit; | 405 | goto exit; |
406 | c->last_chipselect = -1; | 406 | c->last_chipselect = -1; |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d20cb545a6e4..60a8f55a0cc7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1407,7 +1407,11 @@ fail: | |||
1407 | 1407 | ||
1408 | 1408 | ||
1409 | /** | 1409 | /** |
1410 | * Similar to usb_disconnect() | 1410 | * usb_deauthorize_device - deauthorize a device (usbcore-internal) |
1411 | * @usb_dev: USB device | ||
1412 | * | ||
1413 | * Move the USB device to a very basic state where interfaces are disabled | ||
1414 | * and the device is in fact unconfigured and unusable. | ||
1411 | * | 1415 | * |
1412 | * We share a lock (that we have) with device_del(), so we need to | 1416 | * We share a lock (that we have) with device_del(), so we need to |
1413 | * defer its call. | 1417 | * defer its call. |
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 43722e5a49d1..b624320df903 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c | |||
@@ -1042,7 +1042,8 @@ sisusbcon_set_origin(struct vc_data *c) | |||
1042 | 1042 | ||
1043 | /* Interface routine */ | 1043 | /* Interface routine */ |
1044 | static int | 1044 | static int |
1045 | sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) | 1045 | sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows, |
1046 | unsigned int user) | ||
1046 | { | 1047 | { |
1047 | struct sisusb_usb_data *sisusb; | 1048 | struct sisusb_usb_data *sisusb; |
1048 | int fh; | 1049 | int fh; |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5216c11d4dec..efe474e2cc3b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -5,8 +5,9 @@ | |||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | depends on HAS_IOMEM | 6 | depends on HAS_IOMEM |
7 | 7 | ||
8 | source "drivers/video/backlight/Kconfig" | 8 | source "drivers/char/agp/Kconfig" |
9 | source "drivers/video/display/Kconfig" | 9 | |
10 | source "drivers/char/drm/Kconfig" | ||
10 | 11 | ||
11 | config VGASTATE | 12 | config VGASTATE |
12 | tristate | 13 | tristate |
@@ -19,7 +20,7 @@ config VIDEO_OUTPUT_CONTROL | |||
19 | This framework adds support for low-level control of the video | 20 | This framework adds support for low-level control of the video |
20 | output switch. | 21 | output switch. |
21 | 22 | ||
22 | config FB | 23 | menuconfig FB |
23 | tristate "Support for frame buffer devices" | 24 | tristate "Support for frame buffer devices" |
24 | ---help--- | 25 | ---help--- |
25 | The frame buffer device provides an abstraction for the graphics | 26 | The frame buffer device provides an abstraction for the graphics |
@@ -103,6 +104,15 @@ config FB_CFB_IMAGEBLIT | |||
103 | blitting. This is used by drivers that don't provide their own | 104 | blitting. This is used by drivers that don't provide their own |
104 | (accelerated) version. | 105 | (accelerated) version. |
105 | 106 | ||
107 | config FB_CFB_REV_PIXELS_IN_BYTE | ||
108 | bool | ||
109 | depends on FB | ||
110 | default n | ||
111 | ---help--- | ||
112 | Allow generic frame-buffer functions to work on displays with 1, 2 | ||
113 | and 4 bits per pixel depths which has opposite order of pixels in | ||
114 | byte order to bytes in long order. | ||
115 | |||
106 | config FB_SYS_FILLRECT | 116 | config FB_SYS_FILLRECT |
107 | tristate | 117 | tristate |
108 | depends on FB | 118 | depends on FB |
@@ -535,6 +545,15 @@ config FB_VGA16 | |||
535 | To compile this driver as a module, choose M here: the | 545 | To compile this driver as a module, choose M here: the |
536 | module will be called vga16fb. | 546 | module will be called vga16fb. |
537 | 547 | ||
548 | config FB_BF54X_LQ043 | ||
549 | tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" | ||
550 | depends on FB && (BF54x) | ||
551 | select FB_CFB_FILLRECT | ||
552 | select FB_CFB_COPYAREA | ||
553 | select FB_CFB_IMAGEBLIT | ||
554 | help | ||
555 | This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD | ||
556 | |||
538 | config FB_STI | 557 | config FB_STI |
539 | tristate "HP STI frame buffer device support" | 558 | tristate "HP STI frame buffer device support" |
540 | depends on FB && PARISC | 559 | depends on FB && PARISC |
@@ -592,6 +611,24 @@ config FB_TGA | |||
592 | 611 | ||
593 | Say Y if you have one of those. | 612 | Say Y if you have one of those. |
594 | 613 | ||
614 | config FB_UVESA | ||
615 | tristate "Userspace VESA VGA graphics support" | ||
616 | depends on FB && CONNECTOR | ||
617 | select FB_CFB_FILLRECT | ||
618 | select FB_CFB_COPYAREA | ||
619 | select FB_CFB_IMAGEBLIT | ||
620 | select FB_MODE_HELPERS | ||
621 | help | ||
622 | This is the frame buffer driver for generic VBE 2.0 compliant | ||
623 | graphic cards. It can also take advantage of VBE 3.0 features, | ||
624 | such as refresh rate adjustment. | ||
625 | |||
626 | This driver generally provides more features than vesafb but | ||
627 | requires a userspace helper application called 'v86d'. See | ||
628 | <file:Documentation/fb/uvesafb.txt> for more information. | ||
629 | |||
630 | If unsure, say N. | ||
631 | |||
595 | config FB_VESA | 632 | config FB_VESA |
596 | bool "VESA VGA graphics support" | 633 | bool "VESA VGA graphics support" |
597 | depends on (FB = y) && X86 | 634 | depends on (FB = y) && X86 |
@@ -1625,7 +1662,7 @@ config FB_PMAG_BA | |||
1625 | 1662 | ||
1626 | config FB_PMAGB_B | 1663 | config FB_PMAGB_B |
1627 | tristate "PMAGB-B TURBOchannel framebuffer support" | 1664 | tristate "PMAGB-B TURBOchannel framebuffer support" |
1628 | depends on TC | 1665 | depends on FB && TC |
1629 | select FB_CFB_FILLRECT | 1666 | select FB_CFB_FILLRECT |
1630 | select FB_CFB_COPYAREA | 1667 | select FB_CFB_COPYAREA |
1631 | select FB_CFB_IMAGEBLIT | 1668 | select FB_CFB_IMAGEBLIT |
@@ -1793,7 +1830,7 @@ config FB_PNX4008_DUM_RGB | |||
1793 | 1830 | ||
1794 | config FB_IBM_GXT4500 | 1831 | config FB_IBM_GXT4500 |
1795 | tristate "Framebuffer support for IBM GXT4500P adaptor" | 1832 | tristate "Framebuffer support for IBM GXT4500P adaptor" |
1796 | depends on PPC | 1833 | depends on FB && PPC |
1797 | select FB_CFB_FILLRECT | 1834 | select FB_CFB_FILLRECT |
1798 | select FB_CFB_COPYAREA | 1835 | select FB_CFB_COPYAREA |
1799 | select FB_CFB_IMAGEBLIT | 1836 | select FB_CFB_IMAGEBLIT |
@@ -1833,10 +1870,6 @@ config FB_XILINX | |||
1833 | framebuffer. ML300 carries a 640*480 LCD display on the board, | 1870 | framebuffer. ML300 carries a 640*480 LCD display on the board, |
1834 | ML403 uses a standard DB15 VGA connector. | 1871 | ML403 uses a standard DB15 VGA connector. |
1835 | 1872 | ||
1836 | if ARCH_OMAP | ||
1837 | source "drivers/video/omap/Kconfig" | ||
1838 | endif | ||
1839 | |||
1840 | config FB_VIRTUAL | 1873 | config FB_VIRTUAL |
1841 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" | 1874 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" |
1842 | depends on FB | 1875 | depends on FB |
@@ -1860,6 +1893,13 @@ config FB_VIRTUAL | |||
1860 | 1893 | ||
1861 | If unsure, say N. | 1894 | If unsure, say N. |
1862 | 1895 | ||
1896 | if ARCH_OMAP | ||
1897 | source "drivers/video/omap/Kconfig" | ||
1898 | endif | ||
1899 | |||
1900 | source "drivers/video/backlight/Kconfig" | ||
1901 | source "drivers/video/display/Kconfig" | ||
1902 | |||
1863 | if VT | 1903 | if VT |
1864 | source "drivers/video/console/Kconfig" | 1904 | source "drivers/video/console/Kconfig" |
1865 | endif | 1905 | endif |
@@ -1869,4 +1909,3 @@ if FB || SGI_NEWPORT_CONSOLE | |||
1869 | endif | 1909 | endif |
1870 | 1910 | ||
1871 | endmenu | 1911 | endmenu |
1872 | |||
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 06eec7b182b7..59d6c45a910d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -115,10 +115,12 @@ obj-$(CONFIG_FB_XILINX) += xilinxfb.o | |||
115 | obj-$(CONFIG_FB_OMAP) += omap/ | 115 | obj-$(CONFIG_FB_OMAP) += omap/ |
116 | 116 | ||
117 | # Platform or fallback drivers go here | 117 | # Platform or fallback drivers go here |
118 | obj-$(CONFIG_FB_UVESA) += uvesafb.o | ||
118 | obj-$(CONFIG_FB_VESA) += vesafb.o | 119 | obj-$(CONFIG_FB_VESA) += vesafb.o |
119 | obj-$(CONFIG_FB_IMAC) += imacfb.o | 120 | obj-$(CONFIG_FB_IMAC) += imacfb.o |
120 | obj-$(CONFIG_FB_VGA16) += vga16fb.o | 121 | obj-$(CONFIG_FB_VGA16) += vga16fb.o |
121 | obj-$(CONFIG_FB_OF) += offb.o | 122 | obj-$(CONFIG_FB_OF) += offb.o |
123 | obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o | ||
122 | 124 | ||
123 | # the test framebuffer is last | 125 | # the test framebuffer is last |
124 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o | 126 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o |
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 1a849b870bcc..f2e243c353f9 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c | |||
@@ -52,7 +52,7 @@ | |||
52 | #include <linux/init.h> | 52 | #include <linux/init.h> |
53 | #include <linux/ioport.h> | 53 | #include <linux/ioport.h> |
54 | 54 | ||
55 | #include <asm/uaccess.h> | 55 | #include <linux/uaccess.h> |
56 | #include <asm/system.h> | 56 | #include <asm/system.h> |
57 | #include <asm/irq.h> | 57 | #include <asm/irq.h> |
58 | #include <asm/amigahw.h> | 58 | #include <asm/amigahw.h> |
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index db15baca3f7b..c3431691c9f2 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c | |||
@@ -48,7 +48,7 @@ | |||
48 | #include <linux/arcfb.h> | 48 | #include <linux/arcfb.h> |
49 | #include <linux/platform_device.h> | 49 | #include <linux/platform_device.h> |
50 | 50 | ||
51 | #include <asm/uaccess.h> | 51 | #include <linux/uaccess.h> |
52 | 52 | ||
53 | #define floor8(a) (a&(~0x07)) | 53 | #define floor8(a) (a&(~0x07)) |
54 | #define floorXres(a,xres) (a&(~(xres - 1))) | 54 | #define floorXres(a,xres) (a&(~(xres - 1))) |
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 0038a0541c7e..5d4fbaa53a6c 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c | |||
@@ -58,7 +58,7 @@ | |||
58 | #include <linux/interrupt.h> | 58 | #include <linux/interrupt.h> |
59 | 59 | ||
60 | #include <asm/setup.h> | 60 | #include <asm/setup.h> |
61 | #include <asm/uaccess.h> | 61 | #include <linux/uaccess.h> |
62 | #include <asm/pgtable.h> | 62 | #include <asm/pgtable.h> |
63 | #include <asm/irq.h> | 63 | #include <asm/irq.h> |
64 | #include <asm/io.h> | 64 | #include <asm/io.h> |
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index dca2eb8f2dde..3e9d28bcd9f8 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h | |||
@@ -188,6 +188,7 @@ | |||
188 | #define PCI_CHIP_MACH64VT 0x5654 | 188 | #define PCI_CHIP_MACH64VT 0x5654 |
189 | #define PCI_CHIP_MACH64VU 0x5655 | 189 | #define PCI_CHIP_MACH64VU 0x5655 |
190 | #define PCI_CHIP_MACH64VV 0x5656 | 190 | #define PCI_CHIP_MACH64VV 0x5656 |
191 | #define PCI_CHIP_RC410_5A62 0x5A62 | ||
191 | #define PCI_CHIP_RS300_5834 0x5834 | 192 | #define PCI_CHIP_RS300_5834 0x5834 |
192 | #define PCI_CHIP_RS300_5835 0x5835 | 193 | #define PCI_CHIP_RS300_5835 0x5835 |
193 | #define PCI_CHIP_RS300_5836 0x5836 | 194 | #define PCI_CHIP_RS300_5836 0x5836 |
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index cfcbe37d2d70..cbd3308b6690 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #include <linux/vmalloc.h> | 56 | #include <linux/vmalloc.h> |
57 | #include <linux/delay.h> | 57 | #include <linux/delay.h> |
58 | #include <linux/interrupt.h> | 58 | #include <linux/interrupt.h> |
59 | #include <asm/uaccess.h> | 59 | #include <linux/uaccess.h> |
60 | #include <linux/fb.h> | 60 | #include <linux/fb.h> |
61 | #include <linux/init.h> | 61 | #include <linux/init.h> |
62 | #include <linux/pci.h> | 62 | #include <linux/pci.h> |
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index dc62f8e282b4..7691e73823d3 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h | |||
@@ -126,6 +126,7 @@ union aty_pll { | |||
126 | */ | 126 | */ |
127 | 127 | ||
128 | struct atyfb_par { | 128 | struct atyfb_par { |
129 | u32 pseudo_palette[16]; | ||
129 | struct { u8 red, green, blue; } palette[256]; | 130 | struct { u8 red, green, blue; } palette[256]; |
130 | const struct aty_dac_ops *dac_ops; | 131 | const struct aty_dac_ops *dac_ops; |
131 | const struct aty_pll_ops *pll_ops; | 132 | const struct aty_pll_ops *pll_ops; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index bc6f0096aa04..abe0c435a664 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -68,7 +68,7 @@ | |||
68 | #include <linux/backlight.h> | 68 | #include <linux/backlight.h> |
69 | 69 | ||
70 | #include <asm/io.h> | 70 | #include <asm/io.h> |
71 | #include <asm/uaccess.h> | 71 | #include <linux/uaccess.h> |
72 | 72 | ||
73 | #include <video/mach64.h> | 73 | #include <video/mach64.h> |
74 | #include "atyfb.h" | 74 | #include "atyfb.h" |
@@ -541,8 +541,6 @@ static char ram_off[] __devinitdata = "OFF"; | |||
541 | #endif /* CONFIG_FB_ATY_CT */ | 541 | #endif /* CONFIG_FB_ATY_CT */ |
542 | 542 | ||
543 | 543 | ||
544 | static u32 pseudo_palette[16]; | ||
545 | |||
546 | #ifdef CONFIG_FB_ATY_GX | 544 | #ifdef CONFIG_FB_ATY_GX |
547 | static char *aty_gx_ram[8] __devinitdata = { | 545 | static char *aty_gx_ram[8] __devinitdata = { |
548 | ram_dram, ram_vram, ram_vram, ram_dram, | 546 | ram_dram, ram_vram, ram_vram, ram_dram, |
@@ -2577,7 +2575,7 @@ static int __devinit aty_init(struct fb_info *info) | |||
2577 | #endif | 2575 | #endif |
2578 | 2576 | ||
2579 | info->fbops = &atyfb_ops; | 2577 | info->fbops = &atyfb_ops; |
2580 | info->pseudo_palette = pseudo_palette; | 2578 | info->pseudo_palette = par->pseudo_palette; |
2581 | info->flags = FBINFO_DEFAULT | | 2579 | info->flags = FBINFO_DEFAULT | |
2582 | FBINFO_HWACCEL_IMAGEBLIT | | 2580 | FBINFO_HWACCEL_IMAGEBLIT | |
2583 | FBINFO_HWACCEL_FILLRECT | | 2581 | FBINFO_HWACCEL_FILLRECT | |
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index fe2c6ad01a8d..faf95da8fcbc 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/string.h> | 8 | #include <linux/string.h> |
9 | 9 | ||
10 | #include <asm/io.h> | 10 | #include <asm/io.h> |
11 | #include <asm/uaccess.h> | ||
12 | 11 | ||
13 | #ifdef __sparc__ | 12 | #ifdef __sparc__ |
14 | #include <asm/fbio.h> | 13 | #include <asm/fbio.h> |
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 4b747bdaeea6..1e32b3d13f2e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -69,7 +69,7 @@ | |||
69 | #include <linux/device.h> | 69 | #include <linux/device.h> |
70 | 70 | ||
71 | #include <asm/io.h> | 71 | #include <asm/io.h> |
72 | #include <asm/uaccess.h> | 72 | #include <linux/uaccess.h> |
73 | 73 | ||
74 | #ifdef CONFIG_PPC_OF | 74 | #ifdef CONFIG_PPC_OF |
75 | 75 | ||
@@ -145,6 +145,8 @@ static struct pci_device_id radeonfb_pci_table[] = { | |||
145 | /* 9000/Pro */ | 145 | /* 9000/Pro */ |
146 | CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2), | 146 | CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2), |
147 | CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2), | 147 | CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2), |
148 | |||
149 | CHIP_DEF(PCI_CHIP_RC410_5A62, RC410, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), | ||
148 | /* Mobility 9100 IGP (U3) */ | 150 | /* Mobility 9100 IGP (U3) */ |
149 | CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), | 151 | CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), |
150 | CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), | 152 | CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), |
@@ -1999,6 +2001,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) | |||
1999 | if ((rinfo->family == CHIP_FAMILY_RS100) || | 2001 | if ((rinfo->family == CHIP_FAMILY_RS100) || |
2000 | (rinfo->family == CHIP_FAMILY_RS200) || | 2002 | (rinfo->family == CHIP_FAMILY_RS200) || |
2001 | (rinfo->family == CHIP_FAMILY_RS300) || | 2003 | (rinfo->family == CHIP_FAMILY_RS300) || |
2004 | (rinfo->family == CHIP_FAMILY_RC410) || | ||
2002 | (rinfo->family == CHIP_FAMILY_RS480) ) { | 2005 | (rinfo->family == CHIP_FAMILY_RS480) ) { |
2003 | u32 tom = INREG(NB_TOM); | 2006 | u32 tom = INREG(NB_TOM); |
2004 | tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); | 2007 | tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); |
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 7c922c7b460b..5eac1ce52e72 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h | |||
@@ -48,6 +48,7 @@ enum radeon_family { | |||
48 | CHIP_FAMILY_RV350, | 48 | CHIP_FAMILY_RV350, |
49 | CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ | 49 | CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ |
50 | CHIP_FAMILY_R420, /* R420/R423/M18 */ | 50 | CHIP_FAMILY_R420, /* R420/R423/M18 */ |
51 | CHIP_FAMILY_RC410, | ||
51 | CHIP_FAMILY_RS480, | 52 | CHIP_FAMILY_RS480, |
52 | CHIP_FAMILY_LAST, | 53 | CHIP_FAMILY_LAST, |
53 | }; | 54 | }; |
@@ -66,7 +67,8 @@ enum radeon_family { | |||
66 | ((rinfo)->family == CHIP_FAMILY_R350) || \ | 67 | ((rinfo)->family == CHIP_FAMILY_R350) || \ |
67 | ((rinfo)->family == CHIP_FAMILY_RV380) || \ | 68 | ((rinfo)->family == CHIP_FAMILY_RV380) || \ |
68 | ((rinfo)->family == CHIP_FAMILY_R420) || \ | 69 | ((rinfo)->family == CHIP_FAMILY_R420) || \ |
69 | ((rinfo)->family == CHIP_FAMILY_RS480) ) | 70 | ((rinfo)->family == CHIP_FAMILY_RC410) || \ |
71 | ((rinfo)->family == CHIP_FAMILY_RS480)) | ||
70 | 72 | ||
71 | /* | 73 | /* |
72 | * Chip flags | 74 | * Chip flags |
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 92e201e81fbd..26add8898605 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/backlight.h> | 36 | #include <linux/backlight.h> |
37 | #include <linux/lcd.h> | 37 | #include <linux/lcd.h> |
38 | #include <linux/pci.h> | 38 | #include <linux/pci.h> |
39 | #include <asm/uaccess.h> | ||
40 | 39 | ||
41 | /* The LVDS- and panel power controls sits on the | 40 | /* The LVDS- and panel power controls sits on the |
42 | * GPIO port of the ISA bridge. | 41 | * GPIO port of the ISA bridge. |
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 836ab4df0ef2..15fb4d58b5bc 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/fb.h> | 23 | #include <linux/fb.h> |
24 | #include <linux/backlight.h> | 24 | #include <linux/backlight.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <asm/uaccess.h> | ||
27 | 26 | ||
28 | #define PMU_LPCR 0xB0 | 27 | #define PMU_LPCR 0xB0 |
29 | #define SB_MPS1 0x61 | 28 | #define SB_MPS1 0x61 |
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c new file mode 100644 index 000000000000..74d11c318987 --- /dev/null +++ b/drivers/video/bf54x-lq043fb.c | |||
@@ -0,0 +1,786 @@ | |||
1 | /* | ||
2 | * File: drivers/video/bf54x-lq043.c | ||
3 | * Based on: | ||
4 | * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> | ||
5 | * | ||
6 | * Created: | ||
7 | * Description: ADSP-BF54x Framebufer driver | ||
8 | * | ||
9 | * | ||
10 | * Modified: | ||
11 | * Copyright 2004-2007 Analog Devices Inc. | ||
12 | * | ||
13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, see the file COPYING, or write | ||
27 | * to the Free Software Foundation, Inc., | ||
28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
29 | */ | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/tty.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/fb.h> | ||
40 | #include <linux/ioport.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/types.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/timer.h> | ||
46 | #include <linux/device.h> | ||
47 | #include <linux/backlight.h> | ||
48 | #include <linux/lcd.h> | ||
49 | #include <linux/spinlock.h> | ||
50 | #include <linux/dma-mapping.h> | ||
51 | #include <linux/platform_device.h> | ||
52 | |||
53 | #include <asm/blackfin.h> | ||
54 | #include <asm/irq.h> | ||
55 | #include <asm/dpmc.h> | ||
56 | #include <asm/dma-mapping.h> | ||
57 | #include <asm/dma.h> | ||
58 | #include <asm/gpio.h> | ||
59 | #include <asm/portmux.h> | ||
60 | |||
61 | #include <asm/mach/bf54x-lq043.h> | ||
62 | |||
63 | #define NO_BL_SUPPORT | ||
64 | |||
65 | #define DRIVER_NAME "bf54x-lq043" | ||
66 | static char driver_name[] = DRIVER_NAME; | ||
67 | |||
68 | #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 | ||
69 | |||
70 | #define EPPI0_18 {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, \ | ||
71 | P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, \ | ||
72 | P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, P_PPI0_D16, P_PPI0_D17, 0} | ||
73 | |||
74 | #define EPPI0_24 {P_PPI0_D18, P_PPI0_D19, P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, 0} | ||
75 | |||
76 | struct bfin_bf54xfb_info { | ||
77 | struct fb_info *fb; | ||
78 | struct device *dev; | ||
79 | |||
80 | struct bfin_bf54xfb_mach_info *mach_info; | ||
81 | |||
82 | unsigned char *fb_buffer; /* RGB Buffer */ | ||
83 | |||
84 | dma_addr_t dma_handle; | ||
85 | int lq043_mmap; | ||
86 | int lq043_open_cnt; | ||
87 | int irq; | ||
88 | spinlock_t lock; /* lock */ | ||
89 | }; | ||
90 | |||
91 | static int nocursor; | ||
92 | module_param(nocursor, int, 0644); | ||
93 | MODULE_PARM_DESC(nocursor, "cursor enable/disable"); | ||
94 | |||
95 | static int outp_rgb666; | ||
96 | module_param(outp_rgb666, int, 0); | ||
97 | MODULE_PARM_DESC(outp_rgb666, "Output 18-bit RGB666"); | ||
98 | |||
99 | #define LCD_X_RES 480 /*Horizontal Resolution */ | ||
100 | #define LCD_Y_RES 272 /* Vertical Resolution */ | ||
101 | |||
102 | #define LCD_BPP 24 /* Bit Per Pixel */ | ||
103 | #define DMA_BUS_SIZE 32 | ||
104 | |||
105 | /* -- Horizontal synchronizing -- | ||
106 | * | ||
107 | * Timing characteristics taken from the SHARP LQ043T1DG01 datasheet | ||
108 | * (LCY-W-06602A Page 9 of 22) | ||
109 | * | ||
110 | * Clock Frequency 1/Tc Min 7.83 Typ 9.00 Max 9.26 MHz | ||
111 | * | ||
112 | * Period TH - 525 - Clock | ||
113 | * Pulse width THp - 41 - Clock | ||
114 | * Horizontal period THd - 480 - Clock | ||
115 | * Back porch THb - 2 - Clock | ||
116 | * Front porch THf - 2 - Clock | ||
117 | * | ||
118 | * -- Vertical synchronizing -- | ||
119 | * Period TV - 286 - Line | ||
120 | * Pulse width TVp - 10 - Line | ||
121 | * Vertical period TVd - 272 - Line | ||
122 | * Back porch TVb - 2 - Line | ||
123 | * Front porch TVf - 2 - Line | ||
124 | */ | ||
125 | |||
126 | #define LCD_CLK (8*1000*1000) /* 8MHz */ | ||
127 | |||
128 | /* # active data to transfer after Horizontal Delay clock */ | ||
129 | #define EPPI_HCOUNT LCD_X_RES | ||
130 | |||
131 | /* # active lines to transfer after Vertical Delay clock */ | ||
132 | #define EPPI_VCOUNT LCD_Y_RES | ||
133 | |||
134 | /* Samples per Line = 480 (active data) + 45 (padding) */ | ||
135 | #define EPPI_LINE 525 | ||
136 | |||
137 | /* Lines per Frame = 272 (active data) + 14 (padding) */ | ||
138 | #define EPPI_FRAME 286 | ||
139 | |||
140 | /* FS1 (Hsync) Width (Typical)*/ | ||
141 | #define EPPI_FS1W_HBL 41 | ||
142 | |||
143 | /* FS1 (Hsync) Period (Typical) */ | ||
144 | #define EPPI_FS1P_AVPL EPPI_LINE | ||
145 | |||
146 | /* Horizontal Delay clock after assertion of Hsync (Typical) */ | ||
147 | #define EPPI_HDELAY 43 | ||
148 | |||
149 | /* FS2 (Vsync) Width = FS1 (Hsync) Period * 10 */ | ||
150 | #define EPPI_FS2W_LVB (EPPI_LINE * 10) | ||
151 | |||
152 | /* FS2 (Vsync) Period = FS1 (Hsync) Period * Lines per Frame */ | ||
153 | #define EPPI_FS2P_LAVF (EPPI_LINE * EPPI_FRAME) | ||
154 | |||
155 | /* Vertical Delay after assertion of Vsync (2 Lines) */ | ||
156 | #define EPPI_VDELAY 12 | ||
157 | |||
158 | #define EPPI_CLIP 0xFF00FF00 | ||
159 | |||
160 | /* EPPI Control register configuration value for RGB out | ||
161 | * - EPPI as Output | ||
162 | * GP 2 frame sync mode, | ||
163 | * Internal Clock generation disabled, Internal FS generation enabled, | ||
164 | * Receives samples on EPPI_CLK raising edge, Transmits samples on EPPI_CLK falling edge, | ||
165 | * FS1 & FS2 are active high, | ||
166 | * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out) | ||
167 | * DMA Unpacking disabled when RGB Formating is enabled, otherwise DMA unpacking enabled | ||
168 | * Swapping Enabled, | ||
169 | * One (DMA) Channel Mode, | ||
170 | * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output | ||
171 | * Regular watermark - when FIFO is 100% full, | ||
172 | * Urgent watermark - when FIFO is 75% full | ||
173 | */ | ||
174 | |||
175 | #define EPPI_CONTROL (0x20136E2E | SWAPEN) | ||
176 | |||
177 | static inline u16 get_eppi_clkdiv(u32 target_ppi_clk) | ||
178 | { | ||
179 | u32 sclk = get_sclk(); | ||
180 | |||
181 | /* EPPI_CLK = (SCLK) / (2 * (EPPI_CLKDIV[15:0] + 1)) */ | ||
182 | |||
183 | return (((sclk / target_ppi_clk) / 2) - 1); | ||
184 | } | ||
185 | |||
186 | static void config_ppi(struct bfin_bf54xfb_info *fbi) | ||
187 | { | ||
188 | |||
189 | u16 eppi_clkdiv = get_eppi_clkdiv(LCD_CLK); | ||
190 | |||
191 | bfin_write_EPPI0_FS1W_HBL(EPPI_FS1W_HBL); | ||
192 | bfin_write_EPPI0_FS1P_AVPL(EPPI_FS1P_AVPL); | ||
193 | bfin_write_EPPI0_FS2W_LVB(EPPI_FS2W_LVB); | ||
194 | bfin_write_EPPI0_FS2P_LAVF(EPPI_FS2P_LAVF); | ||
195 | bfin_write_EPPI0_CLIP(EPPI_CLIP); | ||
196 | |||
197 | bfin_write_EPPI0_FRAME(EPPI_FRAME); | ||
198 | bfin_write_EPPI0_LINE(EPPI_LINE); | ||
199 | |||
200 | bfin_write_EPPI0_HCOUNT(EPPI_HCOUNT); | ||
201 | bfin_write_EPPI0_HDELAY(EPPI_HDELAY); | ||
202 | bfin_write_EPPI0_VCOUNT(EPPI_VCOUNT); | ||
203 | bfin_write_EPPI0_VDELAY(EPPI_VDELAY); | ||
204 | |||
205 | bfin_write_EPPI0_CLKDIV(eppi_clkdiv); | ||
206 | |||
207 | /* | ||
208 | * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out) | ||
209 | * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output | ||
210 | */ | ||
211 | if (outp_rgb666) | ||
212 | bfin_write_EPPI0_CONTROL((EPPI_CONTROL & ~DLENGTH) | DLEN_18 | | ||
213 | RGB_FMT_EN); | ||
214 | else | ||
215 | bfin_write_EPPI0_CONTROL(((EPPI_CONTROL & ~DLENGTH) | DLEN_24) & | ||
216 | ~RGB_FMT_EN); | ||
217 | |||
218 | |||
219 | } | ||
220 | |||
221 | static int config_dma(struct bfin_bf54xfb_info *fbi) | ||
222 | { | ||
223 | |||
224 | set_dma_config(CH_EPPI0, | ||
225 | set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, | ||
226 | INTR_DISABLE, DIMENSION_2D, | ||
227 | DATA_SIZE_32)); | ||
228 | set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); | ||
229 | set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8); | ||
230 | set_dma_y_count(CH_EPPI0, LCD_Y_RES); | ||
231 | set_dma_y_modify(CH_EPPI0, DMA_BUS_SIZE / 8); | ||
232 | set_dma_start_addr(CH_EPPI0, (unsigned long)fbi->fb_buffer); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int request_ports(struct bfin_bf54xfb_info *fbi) | ||
238 | { | ||
239 | |||
240 | u16 eppi_req_18[] = EPPI0_18; | ||
241 | u16 disp = fbi->mach_info->disp; | ||
242 | |||
243 | if (gpio_request(disp, NULL)) { | ||
244 | printk(KERN_ERR "Requesting GPIO %d faild\n", disp); | ||
245 | return -EFAULT; | ||
246 | } | ||
247 | |||
248 | if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) { | ||
249 | printk(KERN_ERR "Requesting Peripherals faild\n"); | ||
250 | gpio_free(disp); | ||
251 | return -EFAULT; | ||
252 | } | ||
253 | |||
254 | if (!outp_rgb666) { | ||
255 | |||
256 | u16 eppi_req_24[] = EPPI0_24; | ||
257 | |||
258 | if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) { | ||
259 | printk(KERN_ERR "Requesting Peripherals faild\n"); | ||
260 | peripheral_free_list(eppi_req_18); | ||
261 | gpio_free(disp); | ||
262 | return -EFAULT; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | gpio_direction_output(disp); | ||
267 | gpio_set_value(disp, 1); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static void free_ports(struct bfin_bf54xfb_info *fbi) | ||
273 | { | ||
274 | |||
275 | u16 eppi_req_18[] = EPPI0_18; | ||
276 | |||
277 | gpio_free(fbi->mach_info->disp); | ||
278 | |||
279 | peripheral_free_list(eppi_req_18); | ||
280 | |||
281 | if (!outp_rgb666) { | ||
282 | u16 eppi_req_24[] = EPPI0_24; | ||
283 | peripheral_free_list(eppi_req_24); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static int bfin_bf54x_fb_open(struct fb_info *info, int user) | ||
288 | { | ||
289 | struct bfin_bf54xfb_info *fbi = info->par; | ||
290 | |||
291 | spin_lock(&fbi->lock); | ||
292 | fbi->lq043_open_cnt++; | ||
293 | |||
294 | if (fbi->lq043_open_cnt <= 1) { | ||
295 | |||
296 | bfin_write_EPPI0_CONTROL(0); | ||
297 | SSYNC(); | ||
298 | |||
299 | config_dma(fbi); | ||
300 | config_ppi(fbi); | ||
301 | |||
302 | /* start dma */ | ||
303 | enable_dma(CH_EPPI0); | ||
304 | bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); | ||
305 | } | ||
306 | |||
307 | spin_unlock(&fbi->lock); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int bfin_bf54x_fb_release(struct fb_info *info, int user) | ||
313 | { | ||
314 | struct bfin_bf54xfb_info *fbi = info->par; | ||
315 | |||
316 | spin_lock(&fbi->lock); | ||
317 | |||
318 | fbi->lq043_open_cnt--; | ||
319 | fbi->lq043_mmap = 0; | ||
320 | |||
321 | if (fbi->lq043_open_cnt <= 0) { | ||
322 | |||
323 | bfin_write_EPPI0_CONTROL(0); | ||
324 | SSYNC(); | ||
325 | disable_dma(CH_EPPI0); | ||
326 | memset(fbi->fb_buffer, 0, info->fix.smem_len); | ||
327 | } | ||
328 | |||
329 | spin_unlock(&fbi->lock); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, | ||
335 | struct fb_info *info) | ||
336 | { | ||
337 | |||
338 | if (var->bits_per_pixel != LCD_BPP) { | ||
339 | pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, | ||
340 | var->bits_per_pixel); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | if (info->var.xres != var->xres || info->var.yres != var->yres || | ||
345 | info->var.xres_virtual != var->xres_virtual || | ||
346 | info->var.yres_virtual != var->yres_virtual) { | ||
347 | pr_debug("%s: Resolution not supported: X%u x Y%u \n", | ||
348 | __FUNCTION__, var->xres, var->yres); | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Memory limit | ||
354 | */ | ||
355 | |||
356 | if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { | ||
357 | pr_debug("%s: Memory Limit requested yres_virtual = %u\n", | ||
358 | __FUNCTION__, var->yres_virtual); | ||
359 | return -ENOMEM; | ||
360 | } | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
366 | { | ||
367 | |||
368 | struct bfin_bf54xfb_info *fbi = info->par; | ||
369 | |||
370 | if (fbi->lq043_mmap) | ||
371 | return -1; | ||
372 | |||
373 | spin_lock(&fbi->lock); | ||
374 | fbi->lq043_mmap = 1; | ||
375 | spin_unlock(&fbi->lock); | ||
376 | |||
377 | vma->vm_start = (unsigned long)(fbi->fb_buffer); | ||
378 | |||
379 | vma->vm_end = vma->vm_start + info->fix.smem_len; | ||
380 | /* For those who don't understand how mmap works, go read | ||
381 | * Documentation/nommu-mmap.txt. | ||
382 | * For those that do, you will know that the VM_MAYSHARE flag | ||
383 | * must be set in the vma->vm_flags structure on noMMU | ||
384 | * Other flags can be set, and are documented in | ||
385 | * include/linux/mm.h | ||
386 | */ | ||
387 | vma->vm_flags |= VM_MAYSHARE; | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | int bfin_bf54x_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
393 | { | ||
394 | if (nocursor) | ||
395 | return 0; | ||
396 | else | ||
397 | return -EINVAL; /* just to force soft_cursor() call */ | ||
398 | } | ||
399 | |||
400 | static int bfin_bf54x_fb_setcolreg(u_int regno, u_int red, u_int green, | ||
401 | u_int blue, u_int transp, | ||
402 | struct fb_info *info) | ||
403 | { | ||
404 | if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) | ||
405 | return -EINVAL; | ||
406 | |||
407 | if (info->var.grayscale) { | ||
408 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
409 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
410 | } | ||
411 | |||
412 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
413 | |||
414 | u32 value; | ||
415 | /* Place color in the pseudopalette */ | ||
416 | if (regno > 16) | ||
417 | return -EINVAL; | ||
418 | |||
419 | red >>= (16 - info->var.red.length); | ||
420 | green >>= (16 - info->var.green.length); | ||
421 | blue >>= (16 - info->var.blue.length); | ||
422 | |||
423 | value = (red << info->var.red.offset) | | ||
424 | (green << info->var.green.offset) | | ||
425 | (blue << info->var.blue.offset); | ||
426 | value &= 0xFFFFFF; | ||
427 | |||
428 | ((u32 *) (info->pseudo_palette))[regno] = value; | ||
429 | |||
430 | } | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static struct fb_ops bfin_bf54x_fb_ops = { | ||
436 | .owner = THIS_MODULE, | ||
437 | .fb_open = bfin_bf54x_fb_open, | ||
438 | .fb_release = bfin_bf54x_fb_release, | ||
439 | .fb_check_var = bfin_bf54x_fb_check_var, | ||
440 | .fb_fillrect = cfb_fillrect, | ||
441 | .fb_copyarea = cfb_copyarea, | ||
442 | .fb_imageblit = cfb_imageblit, | ||
443 | .fb_mmap = bfin_bf54x_fb_mmap, | ||
444 | .fb_cursor = bfin_bf54x_fb_cursor, | ||
445 | .fb_setcolreg = bfin_bf54x_fb_setcolreg, | ||
446 | }; | ||
447 | |||
448 | #ifndef NO_BL_SUPPORT | ||
449 | static int bl_get_brightness(struct backlight_device *bd) | ||
450 | { | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static struct backlight_ops bfin_lq043fb_bl_ops = { | ||
455 | .get_brightness = bl_get_brightness, | ||
456 | }; | ||
457 | |||
458 | static struct backlight_device *bl_dev; | ||
459 | |||
460 | static int bfin_lcd_get_power(struct lcd_device *dev) | ||
461 | { | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int bfin_lcd_set_power(struct lcd_device *dev, int power) | ||
466 | { | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int bfin_lcd_get_contrast(struct lcd_device *dev) | ||
471 | { | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast) | ||
476 | { | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int bfin_lcd_check_fb(struct fb_info *fi) | ||
482 | { | ||
483 | if (!fi || (fi == &bfin_bf54x_fb)) | ||
484 | return 1; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static struct lcd_ops bfin_lcd_ops = { | ||
489 | .get_power = bfin_lcd_get_power, | ||
490 | .set_power = bfin_lcd_set_power, | ||
491 | .get_contrast = bfin_lcd_get_contrast, | ||
492 | .set_contrast = bfin_lcd_set_contrast, | ||
493 | .check_fb = bfin_lcd_check_fb, | ||
494 | }; | ||
495 | |||
496 | static struct lcd_device *lcd_dev; | ||
497 | #endif | ||
498 | |||
499 | static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) | ||
500 | { | ||
501 | |||
502 | /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/ | ||
503 | |||
504 | u16 status = bfin_read_EPPI0_STATUS(); | ||
505 | |||
506 | bfin_write_EPPI0_STATUS(0xFFFF); | ||
507 | |||
508 | if (status) { | ||
509 | bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN); | ||
510 | disable_dma(CH_EPPI0); | ||
511 | |||
512 | /* start dma */ | ||
513 | enable_dma(CH_EPPI0); | ||
514 | bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); | ||
515 | bfin_write_EPPI0_STATUS(0xFFFF); | ||
516 | } | ||
517 | |||
518 | return IRQ_HANDLED; | ||
519 | } | ||
520 | |||
521 | static int __init bfin_bf54x_probe(struct platform_device *pdev) | ||
522 | { | ||
523 | struct bfin_bf54xfb_info *info; | ||
524 | struct fb_info *fbinfo; | ||
525 | int ret; | ||
526 | |||
527 | printk(KERN_INFO DRIVER_NAME ": FrameBuffer initializing...\n"); | ||
528 | |||
529 | if (request_dma(CH_EPPI0, "CH_EPPI0") < 0) { | ||
530 | printk(KERN_ERR DRIVER_NAME | ||
531 | ": couldn't request CH_EPPI0 DMA\n"); | ||
532 | ret = -EFAULT; | ||
533 | goto out1; | ||
534 | } | ||
535 | |||
536 | fbinfo = | ||
537 | framebuffer_alloc(sizeof(struct bfin_bf54xfb_info), &pdev->dev); | ||
538 | if (!fbinfo) { | ||
539 | ret = -ENOMEM; | ||
540 | goto out2; | ||
541 | } | ||
542 | |||
543 | info = fbinfo->par; | ||
544 | info->fb = fbinfo; | ||
545 | info->dev = &pdev->dev; | ||
546 | |||
547 | platform_set_drvdata(pdev, fbinfo); | ||
548 | |||
549 | strcpy(fbinfo->fix.id, driver_name); | ||
550 | |||
551 | info->mach_info = pdev->dev.platform_data; | ||
552 | |||
553 | if (info->mach_info == NULL) { | ||
554 | dev_err(&pdev->dev, | ||
555 | "no platform data for lcd, cannot attach\n"); | ||
556 | ret = -EINVAL; | ||
557 | goto out3; | ||
558 | } | ||
559 | |||
560 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | ||
561 | fbinfo->fix.type_aux = 0; | ||
562 | fbinfo->fix.xpanstep = 0; | ||
563 | fbinfo->fix.ypanstep = 0; | ||
564 | fbinfo->fix.ywrapstep = 0; | ||
565 | fbinfo->fix.accel = FB_ACCEL_NONE; | ||
566 | fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; | ||
567 | |||
568 | fbinfo->var.nonstd = 0; | ||
569 | fbinfo->var.activate = FB_ACTIVATE_NOW; | ||
570 | fbinfo->var.height = info->mach_info->height; | ||
571 | fbinfo->var.width = info->mach_info->width; | ||
572 | fbinfo->var.accel_flags = 0; | ||
573 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; | ||
574 | |||
575 | fbinfo->fbops = &bfin_bf54x_fb_ops; | ||
576 | fbinfo->flags = FBINFO_FLAG_DEFAULT; | ||
577 | |||
578 | fbinfo->var.xres = info->mach_info->xres.defval; | ||
579 | fbinfo->var.xres_virtual = info->mach_info->xres.defval; | ||
580 | fbinfo->var.yres = info->mach_info->yres.defval; | ||
581 | fbinfo->var.yres_virtual = info->mach_info->yres.defval; | ||
582 | fbinfo->var.bits_per_pixel = info->mach_info->bpp.defval; | ||
583 | |||
584 | fbinfo->var.upper_margin = 0; | ||
585 | fbinfo->var.lower_margin = 0; | ||
586 | fbinfo->var.vsync_len = 0; | ||
587 | |||
588 | fbinfo->var.left_margin = 0; | ||
589 | fbinfo->var.right_margin = 0; | ||
590 | fbinfo->var.hsync_len = 0; | ||
591 | |||
592 | fbinfo->var.red.offset = 16; | ||
593 | fbinfo->var.green.offset = 8; | ||
594 | fbinfo->var.blue.offset = 0; | ||
595 | fbinfo->var.transp.offset = 0; | ||
596 | fbinfo->var.red.length = 8; | ||
597 | fbinfo->var.green.length = 8; | ||
598 | fbinfo->var.blue.length = 8; | ||
599 | fbinfo->var.transp.length = 0; | ||
600 | fbinfo->fix.smem_len = info->mach_info->xres.max * | ||
601 | info->mach_info->yres.max * info->mach_info->bpp.max / 8; | ||
602 | |||
603 | fbinfo->fix.line_length = fbinfo->var.xres_virtual * | ||
604 | fbinfo->var.bits_per_pixel / 8; | ||
605 | |||
606 | info->fb_buffer = | ||
607 | dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, | ||
608 | GFP_KERNEL); | ||
609 | |||
610 | if (NULL == info->fb_buffer) { | ||
611 | printk(KERN_ERR DRIVER_NAME | ||
612 | ": couldn't allocate dma buffer.\n"); | ||
613 | ret = -ENOMEM; | ||
614 | goto out3; | ||
615 | } | ||
616 | |||
617 | memset(info->fb_buffer, 0, fbinfo->fix.smem_len); | ||
618 | |||
619 | fbinfo->screen_base = (void *)info->fb_buffer; | ||
620 | fbinfo->fix.smem_start = (int)info->fb_buffer; | ||
621 | |||
622 | fbinfo->fbops = &bfin_bf54x_fb_ops; | ||
623 | |||
624 | fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | ||
625 | if (!fbinfo->pseudo_palette) { | ||
626 | printk(KERN_ERR DRIVER_NAME | ||
627 | "Fail to allocate pseudo_palette\n"); | ||
628 | |||
629 | ret = -ENOMEM; | ||
630 | goto out4; | ||
631 | } | ||
632 | |||
633 | memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); | ||
634 | |||
635 | if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) | ||
636 | < 0) { | ||
637 | printk(KERN_ERR DRIVER_NAME | ||
638 | "Fail to allocate colormap (%d entries)\n", | ||
639 | BFIN_LCD_NBR_PALETTE_ENTRIES); | ||
640 | ret = -EFAULT; | ||
641 | goto out5; | ||
642 | } | ||
643 | |||
644 | if (request_ports(info)) { | ||
645 | printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n"); | ||
646 | ret = -EFAULT; | ||
647 | goto out6; | ||
648 | } | ||
649 | |||
650 | info->irq = platform_get_irq(pdev, 0); | ||
651 | if (info->irq < 0) { | ||
652 | ret = -EINVAL; | ||
653 | goto out7; | ||
654 | } | ||
655 | |||
656 | if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED, | ||
657 | "PPI ERROR", info) < 0) { | ||
658 | printk(KERN_ERR DRIVER_NAME | ||
659 | ": unable to request PPI ERROR IRQ\n"); | ||
660 | ret = -EFAULT; | ||
661 | goto out7; | ||
662 | } | ||
663 | |||
664 | if (register_framebuffer(fbinfo) < 0) { | ||
665 | printk(KERN_ERR DRIVER_NAME | ||
666 | ": unable to register framebuffer.\n"); | ||
667 | ret = -EINVAL; | ||
668 | goto out8; | ||
669 | } | ||
670 | #ifndef NO_BL_SUPPORT | ||
671 | bl_dev = | ||
672 | backlight_device_register("bf54x-bl", NULL, NULL, | ||
673 | &bfin_lq043fb_bl_ops); | ||
674 | bl_dev->props.max_brightness = 255; | ||
675 | |||
676 | lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); | ||
677 | lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); | ||
678 | #endif | ||
679 | |||
680 | return 0; | ||
681 | |||
682 | out8: | ||
683 | free_irq(info->irq, info); | ||
684 | out7: | ||
685 | free_ports(info); | ||
686 | out6: | ||
687 | fb_dealloc_cmap(&fbinfo->cmap); | ||
688 | out5: | ||
689 | kfree(fbinfo->pseudo_palette); | ||
690 | out4: | ||
691 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
692 | info->dma_handle); | ||
693 | out3: | ||
694 | framebuffer_release(fbinfo); | ||
695 | out2: | ||
696 | free_dma(CH_EPPI0); | ||
697 | out1: | ||
698 | platform_set_drvdata(pdev, NULL); | ||
699 | |||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | static int bfin_bf54x_remove(struct platform_device *pdev) | ||
704 | { | ||
705 | |||
706 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
707 | struct bfin_bf54xfb_info *info = fbinfo->par; | ||
708 | |||
709 | free_dma(CH_EPPI0); | ||
710 | free_irq(info->irq, info); | ||
711 | |||
712 | if (info->fb_buffer != NULL) | ||
713 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
714 | info->dma_handle); | ||
715 | |||
716 | kfree(fbinfo->pseudo_palette); | ||
717 | fb_dealloc_cmap(&fbinfo->cmap); | ||
718 | |||
719 | #ifndef NO_BL_SUPPORT | ||
720 | lcd_device_unregister(lcd_dev); | ||
721 | backlight_device_unregister(bl_dev); | ||
722 | #endif | ||
723 | |||
724 | unregister_framebuffer(fbinfo); | ||
725 | |||
726 | free_ports(info); | ||
727 | |||
728 | printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | #ifdef CONFIG_PM | ||
734 | static int bfin_bf54x_suspend(struct platform_device *pdev, pm_message_t state) | ||
735 | { | ||
736 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
737 | struct bfin_bf54xfb_info *info = fbinfo->par; | ||
738 | |||
739 | bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN); | ||
740 | disable_dma(CH_EPPI0); | ||
741 | bfin_write_EPPI0_STATUS(0xFFFF); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static int bfin_bf54x_resume(struct platform_device *pdev) | ||
747 | { | ||
748 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
749 | struct bfin_bf54xfb_info *info = fbinfo->par; | ||
750 | |||
751 | enable_dma(CH_EPPI0); | ||
752 | bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); | ||
753 | |||
754 | return 0; | ||
755 | } | ||
756 | #else | ||
757 | #define bfin_bf54x_suspend NULL | ||
758 | #define bfin_bf54x_resume NULL | ||
759 | #endif | ||
760 | |||
761 | static struct platform_driver bfin_bf54x_driver = { | ||
762 | .probe = bfin_bf54x_probe, | ||
763 | .remove = bfin_bf54x_remove, | ||
764 | .suspend = bfin_bf54x_suspend, | ||
765 | .resume = bfin_bf54x_resume, | ||
766 | .driver = { | ||
767 | .name = DRIVER_NAME, | ||
768 | .owner = THIS_MODULE, | ||
769 | }, | ||
770 | }; | ||
771 | |||
772 | static int __devinit bfin_bf54x_driver_init(void) | ||
773 | { | ||
774 | return platform_driver_register(&bfin_bf54x_driver); | ||
775 | } | ||
776 | |||
777 | static void __exit bfin_bf54x_driver_cleanup(void) | ||
778 | { | ||
779 | platform_driver_unregister(&bfin_bf54x_driver); | ||
780 | } | ||
781 | |||
782 | MODULE_DESCRIPTION("Blackfin BF54x TFT LCD Driver"); | ||
783 | MODULE_LICENSE("GPL"); | ||
784 | |||
785 | module_init(bfin_bf54x_driver_init); | ||
786 | module_exit(bfin_bf54x_driver_cleanup); | ||
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 032210f45be3..b07e419b12d2 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c | |||
@@ -45,14 +45,14 @@ | |||
45 | 45 | ||
46 | static void | 46 | static void |
47 | bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, | 47 | bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, |
48 | int src_idx, int bits, unsigned n) | 48 | int src_idx, int bits, unsigned n, u32 bswapmask) |
49 | { | 49 | { |
50 | unsigned long first, last; | 50 | unsigned long first, last; |
51 | int const shift = dst_idx-src_idx; | 51 | int const shift = dst_idx-src_idx; |
52 | int left, right; | 52 | int left, right; |
53 | 53 | ||
54 | first = FB_SHIFT_HIGH(~0UL, dst_idx); | 54 | first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); |
55 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); | 55 | last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); |
56 | 56 | ||
57 | if (!shift) { | 57 | if (!shift) { |
58 | // Same alignment for source and dest | 58 | // Same alignment for source and dest |
@@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
94 | FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); | 94 | FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); |
95 | } | 95 | } |
96 | } else { | 96 | } else { |
97 | /* Different alignment for source and dest */ | ||
97 | unsigned long d0, d1; | 98 | unsigned long d0, d1; |
98 | int m; | 99 | int m; |
99 | // Different alignment for source and dest | ||
100 | 100 | ||
101 | right = shift & (bits - 1); | 101 | right = shift & (bits - 1); |
102 | left = -shift & (bits - 1); | 102 | left = -shift & (bits - 1); |
103 | bswapmask &= shift; | ||
103 | 104 | ||
104 | if (dst_idx+n <= bits) { | 105 | if (dst_idx+n <= bits) { |
105 | // Single destination word | 106 | // Single destination word |
106 | if (last) | 107 | if (last) |
107 | first &= last; | 108 | first &= last; |
109 | d0 = FB_READL(src); | ||
110 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
108 | if (shift > 0) { | 111 | if (shift > 0) { |
109 | // Single source word | 112 | // Single source word |
110 | FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); | 113 | d0 >>= right; |
111 | } else if (src_idx+n <= bits) { | 114 | } else if (src_idx+n <= bits) { |
112 | // Single source word | 115 | // Single source word |
113 | FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); | 116 | d0 <<= left;; |
114 | } else { | 117 | } else { |
115 | // 2 source words | 118 | // 2 source words |
116 | d0 = FB_READL(src++); | 119 | d1 = FB_READL(src + 1); |
117 | d1 = FB_READL(src); | 120 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
118 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); | 121 | d0 = d0<<left | d1>>right; |
119 | } | 122 | } |
123 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
124 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
120 | } else { | 125 | } else { |
121 | // Multiple destination words | 126 | // Multiple destination words |
122 | /** We must always remember the last value read, because in case | 127 | /** We must always remember the last value read, because in case |
@@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
125 | overlap with the current long from SRC. We store this value in | 130 | overlap with the current long from SRC. We store this value in |
126 | 'd0'. */ | 131 | 'd0'. */ |
127 | d0 = FB_READL(src++); | 132 | d0 = FB_READL(src++); |
133 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
128 | // Leading bits | 134 | // Leading bits |
129 | if (shift > 0) { | 135 | if (shift > 0) { |
130 | // Single source word | 136 | // Single source word |
131 | FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); | 137 | d1 = d0; |
138 | d0 >>= right; | ||
132 | dst++; | 139 | dst++; |
133 | n -= bits - dst_idx; | 140 | n -= bits - dst_idx; |
134 | } else { | 141 | } else { |
135 | // 2 source words | 142 | // 2 source words |
136 | d1 = FB_READL(src++); | 143 | d1 = FB_READL(src++); |
137 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); | 144 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
138 | d0 = d1; | 145 | |
146 | d0 = d0<<left | d1>>right; | ||
139 | dst++; | 147 | dst++; |
140 | n -= bits - dst_idx; | 148 | n -= bits - dst_idx; |
141 | } | 149 | } |
150 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
151 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
152 | d0 = d1; | ||
142 | 153 | ||
143 | // Main chunk | 154 | // Main chunk |
144 | m = n % bits; | 155 | m = n % bits; |
145 | n /= bits; | 156 | n /= bits; |
146 | while (n >= 4) { | 157 | while ((n >= 4) && !bswapmask) { |
147 | d1 = FB_READL(src++); | 158 | d1 = FB_READL(src++); |
148 | FB_WRITEL(d0 << left | d1 >> right, dst++); | 159 | FB_WRITEL(d0 << left | d1 >> right, dst++); |
149 | d0 = d1; | 160 | d0 = d1; |
@@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
160 | } | 171 | } |
161 | while (n--) { | 172 | while (n--) { |
162 | d1 = FB_READL(src++); | 173 | d1 = FB_READL(src++); |
163 | FB_WRITEL(d0 << left | d1 >> right, dst++); | 174 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
175 | d0 = d0 << left | d1 >> right; | ||
176 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
177 | FB_WRITEL(d0, dst++); | ||
164 | d0 = d1; | 178 | d0 = d1; |
165 | } | 179 | } |
166 | 180 | ||
@@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
168 | if (last) { | 182 | if (last) { |
169 | if (m <= right) { | 183 | if (m <= right) { |
170 | // Single source word | 184 | // Single source word |
171 | FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); | 185 | d0 <<= left; |
172 | } else { | 186 | } else { |
173 | // 2 source words | 187 | // 2 source words |
174 | d1 = FB_READL(src); | 188 | d1 = FB_READL(src); |
175 | FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); | 189 | d1 = fb_rev_pixels_in_long(d1, |
190 | bswapmask); | ||
191 | d0 = d0<<left | d1>>right; | ||
176 | } | 192 | } |
193 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
194 | FB_WRITEL(comp(d0, FB_READL(dst), last), dst); | ||
177 | } | 195 | } |
178 | } | 196 | } |
179 | } | 197 | } |
@@ -185,7 +203,7 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
185 | 203 | ||
186 | static void | 204 | static void |
187 | bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, | 205 | bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, |
188 | int src_idx, int bits, unsigned n) | 206 | int src_idx, int bits, unsigned n, u32 bswapmask) |
189 | { | 207 | { |
190 | unsigned long first, last; | 208 | unsigned long first, last; |
191 | int shift; | 209 | int shift; |
@@ -203,8 +221,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
203 | 221 | ||
204 | shift = dst_idx-src_idx; | 222 | shift = dst_idx-src_idx; |
205 | 223 | ||
206 | first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); | 224 | first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); |
207 | last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); | 225 | last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); |
208 | 226 | ||
209 | if (!shift) { | 227 | if (!shift) { |
210 | // Same alignment for source and dest | 228 | // Same alignment for source and dest |
@@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
247 | } | 265 | } |
248 | } else { | 266 | } else { |
249 | // Different alignment for source and dest | 267 | // Different alignment for source and dest |
268 | unsigned long d0, d1; | ||
269 | int m; | ||
250 | 270 | ||
251 | int const left = -shift & (bits-1); | 271 | int const left = -shift & (bits-1); |
252 | int const right = shift & (bits-1); | 272 | int const right = shift & (bits-1); |
273 | bswapmask &= shift; | ||
253 | 274 | ||
254 | if ((unsigned long)dst_idx+1 >= n) { | 275 | if ((unsigned long)dst_idx+1 >= n) { |
255 | // Single destination word | 276 | // Single destination word |
256 | if (last) | 277 | if (last) |
257 | first &= last; | 278 | first &= last; |
279 | d0 = FB_READL(src); | ||
258 | if (shift < 0) { | 280 | if (shift < 0) { |
259 | // Single source word | 281 | // Single source word |
260 | FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); | 282 | d0 <<= left; |
261 | } else if (1+(unsigned long)src_idx >= n) { | 283 | } else if (1+(unsigned long)src_idx >= n) { |
262 | // Single source word | 284 | // Single source word |
263 | FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); | 285 | d0 >>= right; |
264 | } else { | 286 | } else { |
265 | // 2 source words | 287 | // 2 source words |
266 | FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); | 288 | d1 = FB_READL(src - 1); |
289 | d1 = fb_rev_pixels_in_long(d1, bswapmask); | ||
290 | d0 = d0>>right | d1<<left; | ||
267 | } | 291 | } |
292 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
293 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
268 | } else { | 294 | } else { |
269 | // Multiple destination words | 295 | // Multiple destination words |
270 | /** We must always remember the last value read, because in case | 296 | /** We must always remember the last value read, because in case |
@@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
272 | 1bpp), we always collect one full long for DST and that might | 298 | 1bpp), we always collect one full long for DST and that might |
273 | overlap with the current long from SRC. We store this value in | 299 | overlap with the current long from SRC. We store this value in |
274 | 'd0'. */ | 300 | 'd0'. */ |
275 | unsigned long d0, d1; | ||
276 | int m; | ||
277 | 301 | ||
278 | d0 = FB_READL(src--); | 302 | d0 = FB_READL(src--); |
303 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
279 | // Leading bits | 304 | // Leading bits |
280 | if (shift < 0) { | 305 | if (shift < 0) { |
281 | // Single source word | 306 | // Single source word |
282 | FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); | 307 | d1 = d0; |
308 | d0 <<= left; | ||
283 | } else { | 309 | } else { |
284 | // 2 source words | 310 | // 2 source words |
285 | d1 = FB_READL(src--); | 311 | d1 = FB_READL(src--); |
286 | FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); | 312 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
287 | d0 = d1; | 313 | d0 = d0>>right | d1<<left; |
288 | } | 314 | } |
315 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
316 | FB_WRITEL(comp(d0, FB_READL(dst), first), dst); | ||
317 | d0 = d1; | ||
289 | dst--; | 318 | dst--; |
290 | n -= dst_idx+1; | 319 | n -= dst_idx+1; |
291 | 320 | ||
292 | // Main chunk | 321 | // Main chunk |
293 | m = n % bits; | 322 | m = n % bits; |
294 | n /= bits; | 323 | n /= bits; |
295 | while (n >= 4) { | 324 | while ((n >= 4) && !bswapmask) { |
296 | d1 = FB_READL(src--); | 325 | d1 = FB_READL(src--); |
297 | FB_WRITEL(d0 >> right | d1 << left, dst--); | 326 | FB_WRITEL(d0 >> right | d1 << left, dst--); |
298 | d0 = d1; | 327 | d0 = d1; |
@@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
309 | } | 338 | } |
310 | while (n--) { | 339 | while (n--) { |
311 | d1 = FB_READL(src--); | 340 | d1 = FB_READL(src--); |
312 | FB_WRITEL(d0 >> right | d1 << left, dst--); | 341 | d1 = fb_rev_pixels_in_long(d1, bswapmask); |
342 | d0 = d0 >> right | d1 << left; | ||
343 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
344 | FB_WRITEL(d0, dst--); | ||
313 | d0 = d1; | 345 | d0 = d1; |
314 | } | 346 | } |
315 | 347 | ||
@@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
317 | if (last) { | 349 | if (last) { |
318 | if (m <= left) { | 350 | if (m <= left) { |
319 | // Single source word | 351 | // Single source word |
320 | FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); | 352 | d0 >>= right; |
321 | } else { | 353 | } else { |
322 | // 2 source words | 354 | // 2 source words |
323 | d1 = FB_READL(src); | 355 | d1 = FB_READL(src); |
324 | FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); | 356 | d1 = fb_rev_pixels_in_long(d1, |
357 | bswapmask); | ||
358 | d0 = d0>>right | d1<<left; | ||
325 | } | 359 | } |
360 | d0 = fb_rev_pixels_in_long(d0, bswapmask); | ||
361 | FB_WRITEL(comp(d0, FB_READL(dst), last), dst); | ||
326 | } | 362 | } |
327 | } | 363 | } |
328 | } | 364 | } |
@@ -336,6 +372,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
336 | unsigned long __iomem *dst = NULL, *src = NULL; | 372 | unsigned long __iomem *dst = NULL, *src = NULL; |
337 | int bits = BITS_PER_LONG, bytes = bits >> 3; | 373 | int bits = BITS_PER_LONG, bytes = bits >> 3; |
338 | int dst_idx = 0, src_idx = 0, rev_copy = 0; | 374 | int dst_idx = 0, src_idx = 0, rev_copy = 0; |
375 | u32 bswapmask = fb_compute_bswapmask(p); | ||
339 | 376 | ||
340 | if (p->state != FBINFO_STATE_RUNNING) | 377 | if (p->state != FBINFO_STATE_RUNNING) |
341 | return; | 378 | return; |
@@ -368,7 +405,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
368 | src += src_idx >> (ffs(bits) - 1); | 405 | src += src_idx >> (ffs(bits) - 1); |
369 | src_idx &= (bytes - 1); | 406 | src_idx &= (bytes - 1); |
370 | bitcpy_rev(dst, dst_idx, src, src_idx, bits, | 407 | bitcpy_rev(dst, dst_idx, src, src_idx, bits, |
371 | width*p->var.bits_per_pixel); | 408 | width*p->var.bits_per_pixel, bswapmask); |
372 | } | 409 | } |
373 | } else { | 410 | } else { |
374 | while (height--) { | 411 | while (height--) { |
@@ -377,7 +414,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) | |||
377 | src += src_idx >> (ffs(bits) - 1); | 414 | src += src_idx >> (ffs(bits) - 1); |
378 | src_idx &= (bytes - 1); | 415 | src_idx &= (bytes - 1); |
379 | bitcpy(dst, dst_idx, src, src_idx, bits, | 416 | bitcpy(dst, dst_idx, src, src_idx, bits, |
380 | width*p->var.bits_per_pixel); | 417 | width*p->var.bits_per_pixel, bswapmask); |
381 | dst_idx += bits_per_line; | 418 | dst_idx += bits_per_line; |
382 | src_idx += bits_per_line; | 419 | src_idx += bits_per_line; |
383 | } | 420 | } |
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 71623b4f8ca2..23d70a12e4da 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c | |||
@@ -36,15 +36,16 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | static void | 38 | static void |
39 | bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) | 39 | bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, |
40 | unsigned n, int bits, u32 bswapmask) | ||
40 | { | 41 | { |
41 | unsigned long first, last; | 42 | unsigned long first, last; |
42 | 43 | ||
43 | if (!n) | 44 | if (!n) |
44 | return; | 45 | return; |
45 | 46 | ||
46 | first = FB_SHIFT_HIGH(~0UL, dst_idx); | 47 | first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); |
47 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); | 48 | last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); |
48 | 49 | ||
49 | if (dst_idx+n <= bits) { | 50 | if (dst_idx+n <= bits) { |
50 | // Single word | 51 | // Single word |
@@ -146,7 +147,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, | |||
146 | * Aligned pattern invert using 32/64-bit memory accesses | 147 | * Aligned pattern invert using 32/64-bit memory accesses |
147 | */ | 148 | */ |
148 | static void | 149 | static void |
149 | bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) | 150 | bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, |
151 | unsigned n, int bits, u32 bswapmask) | ||
150 | { | 152 | { |
151 | unsigned long val = pat, dat; | 153 | unsigned long val = pat, dat; |
152 | unsigned long first, last; | 154 | unsigned long first, last; |
@@ -154,8 +156,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, | |||
154 | if (!n) | 156 | if (!n) |
155 | return; | 157 | return; |
156 | 158 | ||
157 | first = FB_SHIFT_HIGH(~0UL, dst_idx); | 159 | first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); |
158 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); | 160 | last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); |
159 | 161 | ||
160 | if (dst_idx+n <= bits) { | 162 | if (dst_idx+n <= bits) { |
161 | // Single word | 163 | // Single word |
@@ -303,8 +305,10 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) | |||
303 | if (p->fbops->fb_sync) | 305 | if (p->fbops->fb_sync) |
304 | p->fbops->fb_sync(p); | 306 | p->fbops->fb_sync(p); |
305 | if (!left) { | 307 | if (!left) { |
308 | u32 bswapmask = fb_compute_bswapmask(p); | ||
306 | void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, | 309 | void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, |
307 | unsigned long pat, unsigned n, int bits) = NULL; | 310 | unsigned long pat, unsigned n, int bits, |
311 | u32 bswapmask) = NULL; | ||
308 | 312 | ||
309 | switch (rect->rop) { | 313 | switch (rect->rop) { |
310 | case ROP_XOR: | 314 | case ROP_XOR: |
@@ -321,7 +325,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) | |||
321 | while (height--) { | 325 | while (height--) { |
322 | dst += dst_idx >> (ffs(bits) - 1); | 326 | dst += dst_idx >> (ffs(bits) - 1); |
323 | dst_idx &= (bits - 1); | 327 | dst_idx &= (bits - 1); |
324 | fill_op32(dst, dst_idx, pat, width*bpp, bits); | 328 | fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); |
325 | dst_idx += p->fix.line_length*8; | 329 | dst_idx += p->fix.line_length*8; |
326 | } | 330 | } |
327 | } else { | 331 | } else { |
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 261004473c8e..f598907b42ad 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/fb.h> | 34 | #include <linux/fb.h> |
35 | #include <asm/types.h> | 35 | #include <asm/types.h> |
36 | #include "fb_draw.h" | ||
36 | 37 | ||
37 | #define DEBUG | 38 | #define DEBUG |
38 | 39 | ||
@@ -87,6 +88,7 @@ static inline void color_imageblit(const struct fb_image *image, | |||
87 | u32 null_bits = 32 - bpp; | 88 | u32 null_bits = 32 - bpp; |
88 | u32 *palette = (u32 *) p->pseudo_palette; | 89 | u32 *palette = (u32 *) p->pseudo_palette; |
89 | const u8 *src = image->data; | 90 | const u8 *src = image->data; |
91 | u32 bswapmask = fb_compute_bswapmask(p); | ||
90 | 92 | ||
91 | dst2 = (u32 __iomem *) dst1; | 93 | dst2 = (u32 __iomem *) dst1; |
92 | for (i = image->height; i--; ) { | 94 | for (i = image->height; i--; ) { |
@@ -96,7 +98,7 @@ static inline void color_imageblit(const struct fb_image *image, | |||
96 | val = 0; | 98 | val = 0; |
97 | 99 | ||
98 | if (start_index) { | 100 | if (start_index) { |
99 | u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index)); | 101 | u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); |
100 | val = FB_READL(dst) & start_mask; | 102 | val = FB_READL(dst) & start_mask; |
101 | shift = start_index; | 103 | shift = start_index; |
102 | } | 104 | } |
@@ -107,7 +109,7 @@ static inline void color_imageblit(const struct fb_image *image, | |||
107 | else | 109 | else |
108 | color = *src; | 110 | color = *src; |
109 | color <<= FB_LEFT_POS(bpp); | 111 | color <<= FB_LEFT_POS(bpp); |
110 | val |= FB_SHIFT_HIGH(color, shift); | 112 | val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); |
111 | if (shift >= null_bits) { | 113 | if (shift >= null_bits) { |
112 | FB_WRITEL(val, dst++); | 114 | FB_WRITEL(val, dst++); |
113 | 115 | ||
@@ -119,7 +121,7 @@ static inline void color_imageblit(const struct fb_image *image, | |||
119 | src++; | 121 | src++; |
120 | } | 122 | } |
121 | if (shift) { | 123 | if (shift) { |
122 | u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); | 124 | u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); |
123 | 125 | ||
124 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | 126 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); |
125 | } | 127 | } |
@@ -147,7 +149,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
147 | u32 spitch = (image->width+7)/8; | 149 | u32 spitch = (image->width+7)/8; |
148 | const u8 *src = image->data, *s; | 150 | const u8 *src = image->data, *s; |
149 | u32 i, j, l; | 151 | u32 i, j, l; |
150 | 152 | u32 bswapmask = fb_compute_bswapmask(p); | |
153 | |||
151 | dst2 = (u32 __iomem *) dst1; | 154 | dst2 = (u32 __iomem *) dst1; |
152 | fgcolor <<= FB_LEFT_POS(bpp); | 155 | fgcolor <<= FB_LEFT_POS(bpp); |
153 | bgcolor <<= FB_LEFT_POS(bpp); | 156 | bgcolor <<= FB_LEFT_POS(bpp); |
@@ -161,7 +164,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
161 | 164 | ||
162 | /* write leading bits */ | 165 | /* write leading bits */ |
163 | if (start_index) { | 166 | if (start_index) { |
164 | u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); | 167 | u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); |
165 | val = FB_READL(dst) & start_mask; | 168 | val = FB_READL(dst) & start_mask; |
166 | shift = start_index; | 169 | shift = start_index; |
167 | } | 170 | } |
@@ -169,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
169 | while (j--) { | 172 | while (j--) { |
170 | l--; | 173 | l--; |
171 | color = (*s & (1 << l)) ? fgcolor : bgcolor; | 174 | color = (*s & (1 << l)) ? fgcolor : bgcolor; |
172 | val |= FB_SHIFT_HIGH(color, shift); | 175 | val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); |
173 | 176 | ||
174 | /* Did the bitshift spill bits to the next long? */ | 177 | /* Did the bitshift spill bits to the next long? */ |
175 | if (shift >= null_bits) { | 178 | if (shift >= null_bits) { |
@@ -184,7 +187,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
184 | 187 | ||
185 | /* write trailing bits */ | 188 | /* write trailing bits */ |
186 | if (shift) { | 189 | if (shift) { |
187 | u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); | 190 | u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); |
188 | 191 | ||
189 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | 192 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); |
190 | } | 193 | } |
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 8269d704ab2a..ce22bf5de350 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/delay.h> | 45 | #include <linux/delay.h> |
46 | #include <linux/fb.h> | 46 | #include <linux/fb.h> |
47 | #include <linux/init.h> | 47 | #include <linux/init.h> |
48 | #include <linux/selection.h> | ||
49 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
50 | 49 | ||
51 | #ifdef CONFIG_ZORRO | 50 | #ifdef CONFIG_ZORRO |
@@ -59,14 +58,13 @@ | |||
59 | #endif | 58 | #endif |
60 | #ifdef CONFIG_PPC_PREP | 59 | #ifdef CONFIG_PPC_PREP |
61 | #include <asm/machdep.h> | 60 | #include <asm/machdep.h> |
62 | #define isPReP (machine_is(prep)) | 61 | #define isPReP machine_is(prep) |
63 | #else | 62 | #else |
64 | #define isPReP 0 | 63 | #define isPReP 0 |
65 | #endif | 64 | #endif |
66 | 65 | ||
67 | #include "video/vga.h" | 66 | #include <video/vga.h> |
68 | #include "video/cirrus.h" | 67 | #include <video/cirrus.h> |
69 | |||
70 | 68 | ||
71 | /***************************************************************** | 69 | /***************************************************************** |
72 | * | 70 | * |
@@ -82,7 +80,8 @@ | |||
82 | 80 | ||
83 | /* debug output */ | 81 | /* debug output */ |
84 | #ifdef CIRRUSFB_DEBUG | 82 | #ifdef CIRRUSFB_DEBUG |
85 | #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) | 83 | #define DPRINTK(fmt, args...) \ |
84 | printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) | ||
86 | #else | 85 | #else |
87 | #define DPRINTK(fmt, args...) | 86 | #define DPRINTK(fmt, args...) |
88 | #endif | 87 | #endif |
@@ -90,19 +89,15 @@ | |||
90 | /* debugging assertions */ | 89 | /* debugging assertions */ |
91 | #ifndef CIRRUSFB_NDEBUG | 90 | #ifndef CIRRUSFB_NDEBUG |
92 | #define assert(expr) \ | 91 | #define assert(expr) \ |
93 | if(!(expr)) { \ | 92 | if (!(expr)) { \ |
94 | printk( "Assertion failed! %s,%s,%s,line=%d\n",\ | 93 | printk("Assertion failed! %s,%s,%s,line=%d\n", \ |
95 | #expr,__FILE__,__FUNCTION__,__LINE__); \ | 94 | #expr, __FILE__, __FUNCTION__, __LINE__); \ |
96 | } | 95 | } |
97 | #else | 96 | #else |
98 | #define assert(expr) | 97 | #define assert(expr) |
99 | #endif | 98 | #endif |
100 | 99 | ||
101 | #define MB_ (1024*1024) | 100 | #define MB_ (1024 * 1024) |
102 | #define KB_ (1024) | ||
103 | |||
104 | #define MAX_NUM_BOARDS 7 | ||
105 | |||
106 | 101 | ||
107 | /***************************************************************** | 102 | /***************************************************************** |
108 | * | 103 | * |
@@ -111,7 +106,7 @@ | |||
111 | */ | 106 | */ |
112 | 107 | ||
113 | /* board types */ | 108 | /* board types */ |
114 | typedef enum { | 109 | enum cirrus_board { |
115 | BT_NONE = 0, | 110 | BT_NONE = 0, |
116 | BT_SD64, | 111 | BT_SD64, |
117 | BT_PICCOLO, | 112 | BT_PICCOLO, |
@@ -121,13 +116,12 @@ typedef enum { | |||
121 | BT_ALPINE, /* GD543x/4x */ | 116 | BT_ALPINE, /* GD543x/4x */ |
122 | BT_GD5480, | 117 | BT_GD5480, |
123 | BT_LAGUNA, /* GD546x */ | 118 | BT_LAGUNA, /* GD546x */ |
124 | } cirrusfb_board_t; | 119 | }; |
125 | |||
126 | 120 | ||
127 | /* | 121 | /* |
128 | * per-board-type information, used for enumerating and abstracting | 122 | * per-board-type information, used for enumerating and abstracting |
129 | * chip-specific information | 123 | * chip-specific information |
130 | * NOTE: MUST be in the same order as cirrusfb_board_t in order to | 124 | * NOTE: MUST be in the same order as enum cirrus_board in order to |
131 | * use direct indexing on this array | 125 | * use direct indexing on this array |
132 | * NOTE: '__initdata' cannot be used as some of this info | 126 | * NOTE: '__initdata' cannot be used as some of this info |
133 | * is required at runtime. Maybe separate into an init-only and | 127 | * is required at runtime. Maybe separate into an init-only and |
@@ -139,7 +133,8 @@ static const struct cirrusfb_board_info_rec { | |||
139 | /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */ | 133 | /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */ |
140 | bool init_sr07 : 1; /* init SR07 during init_vgachip() */ | 134 | bool init_sr07 : 1; /* init SR07 during init_vgachip() */ |
141 | bool init_sr1f : 1; /* write SR1F during init_vgachip() */ | 135 | bool init_sr1f : 1; /* write SR1F during init_vgachip() */ |
142 | bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */ | 136 | /* construct bit 19 of screen start address */ |
137 | bool scrn_start_bit19 : 1; | ||
143 | 138 | ||
144 | /* initial SR07 value, then for each mode */ | 139 | /* initial SR07 value, then for each mode */ |
145 | unsigned char sr07; | 140 | unsigned char sr07; |
@@ -261,30 +256,28 @@ static const struct cirrusfb_board_info_rec { | |||
261 | } | 256 | } |
262 | }; | 257 | }; |
263 | 258 | ||
264 | |||
265 | #ifdef CONFIG_PCI | 259 | #ifdef CONFIG_PCI |
266 | #define CHIP(id, btype) \ | 260 | #define CHIP(id, btype) \ |
267 | { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } | 261 | { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } |
268 | 262 | ||
269 | static struct pci_device_id cirrusfb_pci_table[] = { | 263 | static struct pci_device_id cirrusfb_pci_table[] = { |
270 | CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ), | 264 | CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE), |
271 | CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ), | 265 | CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE), |
272 | CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ), | 266 | CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE), |
273 | CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */ | 267 | CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */ |
274 | CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ), | 268 | CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE), |
275 | CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ), | 269 | CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE), |
276 | CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */ | 270 | CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */ |
277 | CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */ | 271 | CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */ |
278 | CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ | 272 | CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */ |
279 | CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ | 273 | CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */ |
280 | CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ | 274 | CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/ |
281 | { 0, } | 275 | { 0, } |
282 | }; | 276 | }; |
283 | MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); | 277 | MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); |
284 | #undef CHIP | 278 | #undef CHIP |
285 | #endif /* CONFIG_PCI */ | 279 | #endif /* CONFIG_PCI */ |
286 | 280 | ||
287 | |||
288 | #ifdef CONFIG_ZORRO | 281 | #ifdef CONFIG_ZORRO |
289 | static const struct zorro_device_id cirrusfb_zorro_table[] = { | 282 | static const struct zorro_device_id cirrusfb_zorro_table[] = { |
290 | { | 283 | { |
@@ -294,7 +287,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = { | |||
294 | .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, | 287 | .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, |
295 | .driver_data = BT_PICCOLO, | 288 | .driver_data = BT_PICCOLO, |
296 | }, { | 289 | }, { |
297 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, | 290 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, |
298 | .driver_data = BT_PICASSO, | 291 | .driver_data = BT_PICASSO, |
299 | }, { | 292 | }, { |
300 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, | 293 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, |
@@ -333,12 +326,7 @@ static const struct { | |||
333 | }; | 326 | }; |
334 | #endif /* CONFIG_ZORRO */ | 327 | #endif /* CONFIG_ZORRO */ |
335 | 328 | ||
336 | |||
337 | struct cirrusfb_regs { | 329 | struct cirrusfb_regs { |
338 | __u32 line_length; /* in BYTES! */ | ||
339 | __u32 visual; | ||
340 | __u32 type; | ||
341 | |||
342 | long freq; | 330 | long freq; |
343 | long nom; | 331 | long nom; |
344 | long den; | 332 | long den; |
@@ -364,37 +352,23 @@ struct cirrusfb_regs { | |||
364 | long VertBlankEnd; | 352 | long VertBlankEnd; |
365 | }; | 353 | }; |
366 | 354 | ||
367 | |||
368 | |||
369 | #ifdef CIRRUSFB_DEBUG | 355 | #ifdef CIRRUSFB_DEBUG |
370 | typedef enum { | 356 | enum cirrusfb_dbg_reg_class { |
371 | CRT, | 357 | CRT, |
372 | SEQ | 358 | SEQ |
373 | } cirrusfb_dbg_reg_class_t; | 359 | }; |
374 | #endif /* CIRRUSFB_DEBUG */ | 360 | #endif /* CIRRUSFB_DEBUG */ |
375 | |||
376 | |||
377 | |||
378 | 361 | ||
379 | /* info about board */ | 362 | /* info about board */ |
380 | struct cirrusfb_info { | 363 | struct cirrusfb_info { |
381 | struct fb_info *info; | ||
382 | |||
383 | u8 __iomem *fbmem; | ||
384 | u8 __iomem *regbase; | 364 | u8 __iomem *regbase; |
385 | u8 __iomem *mem; | 365 | enum cirrus_board btype; |
386 | unsigned long size; | ||
387 | cirrusfb_board_t btype; | ||
388 | unsigned char SFR; /* Shadow of special function register */ | 366 | unsigned char SFR; /* Shadow of special function register */ |
389 | 367 | ||
390 | unsigned long fbmem_phys; | ||
391 | unsigned long fbregs_phys; | ||
392 | |||
393 | struct cirrusfb_regs currentmode; | 368 | struct cirrusfb_regs currentmode; |
394 | int blank_mode; | 369 | int blank_mode; |
395 | 370 | ||
396 | u32 pseudo_palette[16]; | 371 | u32 pseudo_palette[16]; |
397 | struct { u8 red, green, blue, pad; } palette[256]; | ||
398 | 372 | ||
399 | #ifdef CONFIG_ZORRO | 373 | #ifdef CONFIG_ZORRO |
400 | struct zorro_dev *zdev; | 374 | struct zorro_dev *zdev; |
@@ -402,12 +376,11 @@ struct cirrusfb_info { | |||
402 | #ifdef CONFIG_PCI | 376 | #ifdef CONFIG_PCI |
403 | struct pci_dev *pdev; | 377 | struct pci_dev *pdev; |
404 | #endif | 378 | #endif |
405 | void (*unmap)(struct cirrusfb_info *cinfo); | 379 | void (*unmap)(struct fb_info *info); |
406 | }; | 380 | }; |
407 | 381 | ||
408 | |||
409 | static unsigned cirrusfb_def_mode = 1; | 382 | static unsigned cirrusfb_def_mode = 1; |
410 | static int noaccel = 0; | 383 | static int noaccel; |
411 | 384 | ||
412 | /* | 385 | /* |
413 | * Predefined Video Modes | 386 | * Predefined Video Modes |
@@ -441,7 +414,7 @@ static const struct { | |||
441 | .lower_margin = 8, | 414 | .lower_margin = 8, |
442 | .hsync_len = 96, | 415 | .hsync_len = 96, |
443 | .vsync_len = 4, | 416 | .vsync_len = 4, |
444 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 417 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
445 | .vmode = FB_VMODE_NONINTERLACED | 418 | .vmode = FB_VMODE_NONINTERLACED |
446 | } | 419 | } |
447 | }, { | 420 | }, { |
@@ -502,27 +475,29 @@ static const struct { | |||
502 | /****************************************************************************/ | 475 | /****************************************************************************/ |
503 | /**** BEGIN PROTOTYPES ******************************************************/ | 476 | /**** BEGIN PROTOTYPES ******************************************************/ |
504 | 477 | ||
505 | |||
506 | /*--- Interface used by the world ------------------------------------------*/ | 478 | /*--- Interface used by the world ------------------------------------------*/ |
507 | static int cirrusfb_init (void); | 479 | static int cirrusfb_init(void); |
508 | #ifndef MODULE | 480 | #ifndef MODULE |
509 | static int cirrusfb_setup (char *options); | 481 | static int cirrusfb_setup(char *options); |
510 | #endif | 482 | #endif |
511 | 483 | ||
512 | static int cirrusfb_open (struct fb_info *info, int user); | 484 | static int cirrusfb_open(struct fb_info *info, int user); |
513 | static int cirrusfb_release (struct fb_info *info, int user); | 485 | static int cirrusfb_release(struct fb_info *info, int user); |
514 | static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, | 486 | static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
515 | unsigned blue, unsigned transp, | 487 | unsigned blue, unsigned transp, |
516 | struct fb_info *info); | 488 | struct fb_info *info); |
517 | static int cirrusfb_check_var (struct fb_var_screeninfo *var, | 489 | static int cirrusfb_check_var(struct fb_var_screeninfo *var, |
518 | struct fb_info *info); | 490 | struct fb_info *info); |
519 | static int cirrusfb_set_par (struct fb_info *info); | 491 | static int cirrusfb_set_par(struct fb_info *info); |
520 | static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | 492 | static int cirrusfb_pan_display(struct fb_var_screeninfo *var, |
521 | struct fb_info *info); | 493 | struct fb_info *info); |
522 | static int cirrusfb_blank (int blank_mode, struct fb_info *info); | 494 | static int cirrusfb_blank(int blank_mode, struct fb_info *info); |
523 | static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region); | 495 | static void cirrusfb_fillrect(struct fb_info *info, |
524 | static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); | 496 | const struct fb_fillrect *region); |
525 | static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image); | 497 | static void cirrusfb_copyarea(struct fb_info *info, |
498 | const struct fb_copyarea *area); | ||
499 | static void cirrusfb_imageblit(struct fb_info *info, | ||
500 | const struct fb_image *image); | ||
526 | 501 | ||
527 | /* function table of the above functions */ | 502 | /* function table of the above functions */ |
528 | static struct fb_ops cirrusfb_ops = { | 503 | static struct fb_ops cirrusfb_ops = { |
@@ -540,68 +515,68 @@ static struct fb_ops cirrusfb_ops = { | |||
540 | }; | 515 | }; |
541 | 516 | ||
542 | /*--- Hardware Specific Routines -------------------------------------------*/ | 517 | /*--- Hardware Specific Routines -------------------------------------------*/ |
543 | static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | 518 | static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, |
544 | struct cirrusfb_regs *regs, | 519 | struct cirrusfb_regs *regs, |
545 | const struct fb_info *info); | 520 | struct fb_info *info); |
546 | /*--- Internal routines ----------------------------------------------------*/ | 521 | /*--- Internal routines ----------------------------------------------------*/ |
547 | static void init_vgachip (struct cirrusfb_info *cinfo); | 522 | static void init_vgachip(struct fb_info *info); |
548 | static void switch_monitor (struct cirrusfb_info *cinfo, int on); | 523 | static void switch_monitor(struct cirrusfb_info *cinfo, int on); |
549 | static void WGen (const struct cirrusfb_info *cinfo, | 524 | static void WGen(const struct cirrusfb_info *cinfo, |
550 | int regnum, unsigned char val); | 525 | int regnum, unsigned char val); |
551 | static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum); | 526 | static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum); |
552 | static void AttrOn (const struct cirrusfb_info *cinfo); | 527 | static void AttrOn(const struct cirrusfb_info *cinfo); |
553 | static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val); | 528 | static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val); |
554 | static void WSFR (struct cirrusfb_info *cinfo, unsigned char val); | 529 | static void WSFR(struct cirrusfb_info *cinfo, unsigned char val); |
555 | static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val); | 530 | static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val); |
556 | static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, | 531 | static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, |
557 | unsigned char green, | 532 | unsigned char red, unsigned char green, unsigned char blue); |
558 | unsigned char blue); | ||
559 | #if 0 | 533 | #if 0 |
560 | static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, | 534 | static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, |
561 | unsigned char *green, | 535 | unsigned char *red, unsigned char *green, |
562 | unsigned char *blue); | 536 | unsigned char *blue); |
563 | #endif | 537 | #endif |
564 | static void cirrusfb_WaitBLT (u8 __iomem *regbase); | 538 | static void cirrusfb_WaitBLT(u8 __iomem *regbase); |
565 | static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, | 539 | static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, |
566 | u_short curx, u_short cury, | 540 | u_short curx, u_short cury, |
567 | u_short destx, u_short desty, | 541 | u_short destx, u_short desty, |
568 | u_short width, u_short height, | 542 | u_short width, u_short height, |
569 | u_short line_length); | 543 | u_short line_length); |
570 | static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, | 544 | static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, |
571 | u_short x, u_short y, | 545 | u_short x, u_short y, |
572 | u_short width, u_short height, | 546 | u_short width, u_short height, |
573 | u_char color, u_short line_length); | 547 | u_char color, u_short line_length); |
574 | 548 | ||
575 | static void bestclock (long freq, long *best, | 549 | static void bestclock(long freq, long *best, |
576 | long *nom, long *den, | 550 | long *nom, long *den, |
577 | long *div, long maxfreq); | 551 | long *div, long maxfreq); |
578 | 552 | ||
579 | #ifdef CIRRUSFB_DEBUG | 553 | #ifdef CIRRUSFB_DEBUG |
580 | static void cirrusfb_dump (void); | 554 | static void cirrusfb_dump(void); |
581 | static void cirrusfb_dbg_reg_dump (caddr_t regbase); | 555 | static void cirrusfb_dbg_reg_dump(caddr_t regbase); |
582 | static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...); | 556 | static void cirrusfb_dbg_print_regs(caddr_t regbase, |
583 | static void cirrusfb_dbg_print_byte (const char *name, unsigned char val); | 557 | enum cirrusfb_dbg_reg_class reg_class, ...); |
558 | static void cirrusfb_dbg_print_byte(const char *name, unsigned char val); | ||
584 | #endif /* CIRRUSFB_DEBUG */ | 559 | #endif /* CIRRUSFB_DEBUG */ |
585 | 560 | ||
586 | /*** END PROTOTYPES ********************************************************/ | 561 | /*** END PROTOTYPES ********************************************************/ |
587 | /*****************************************************************************/ | 562 | /*****************************************************************************/ |
588 | /*** BEGIN Interface Used by the World ***************************************/ | 563 | /*** BEGIN Interface Used by the World ***************************************/ |
589 | 564 | ||
590 | static int opencount = 0; | 565 | static int opencount; |
591 | 566 | ||
592 | /*--- Open /dev/fbx ---------------------------------------------------------*/ | 567 | /*--- Open /dev/fbx ---------------------------------------------------------*/ |
593 | static int cirrusfb_open (struct fb_info *info, int user) | 568 | static int cirrusfb_open(struct fb_info *info, int user) |
594 | { | 569 | { |
595 | if (opencount++ == 0) | 570 | if (opencount++ == 0) |
596 | switch_monitor (info->par, 1); | 571 | switch_monitor(info->par, 1); |
597 | return 0; | 572 | return 0; |
598 | } | 573 | } |
599 | 574 | ||
600 | /*--- Close /dev/fbx --------------------------------------------------------*/ | 575 | /*--- Close /dev/fbx --------------------------------------------------------*/ |
601 | static int cirrusfb_release (struct fb_info *info, int user) | 576 | static int cirrusfb_release(struct fb_info *info, int user) |
602 | { | 577 | { |
603 | if (--opencount == 0) | 578 | if (--opencount == 0) |
604 | switch_monitor (info->par, 0); | 579 | switch_monitor(info->par, 0); |
605 | return 0; | 580 | return 0; |
606 | } | 581 | } |
607 | 582 | ||
@@ -610,11 +585,11 @@ static int cirrusfb_release (struct fb_info *info, int user) | |||
610 | /**** BEGIN Hardware specific Routines **************************************/ | 585 | /**** BEGIN Hardware specific Routines **************************************/ |
611 | 586 | ||
612 | /* Get a good MCLK value */ | 587 | /* Get a good MCLK value */ |
613 | static long cirrusfb_get_mclk (long freq, int bpp, long *div) | 588 | static long cirrusfb_get_mclk(long freq, int bpp, long *div) |
614 | { | 589 | { |
615 | long mclk; | 590 | long mclk; |
616 | 591 | ||
617 | assert (div != NULL); | 592 | assert(div != NULL); |
618 | 593 | ||
619 | /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. | 594 | /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. |
620 | * Assume a 64-bit data path for now. The formula is: | 595 | * Assume a 64-bit data path for now. The formula is: |
@@ -624,23 +599,23 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div) | |||
624 | mclk = (mclk * 12) / 10; | 599 | mclk = (mclk * 12) / 10; |
625 | if (mclk < 50000) | 600 | if (mclk < 50000) |
626 | mclk = 50000; | 601 | mclk = 50000; |
627 | DPRINTK ("Use MCLK of %ld kHz\n", mclk); | 602 | DPRINTK("Use MCLK of %ld kHz\n", mclk); |
628 | 603 | ||
629 | /* Calculate value for SR1F. Multiply by 2 so we can round up. */ | 604 | /* Calculate value for SR1F. Multiply by 2 so we can round up. */ |
630 | mclk = ((mclk * 16) / 14318); | 605 | mclk = ((mclk * 16) / 14318); |
631 | mclk = (mclk + 1) / 2; | 606 | mclk = (mclk + 1) / 2; |
632 | DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk); | 607 | DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk); |
633 | 608 | ||
634 | /* Determine if we should use MCLK instead of VCLK, and if so, what we | 609 | /* Determine if we should use MCLK instead of VCLK, and if so, what we |
635 | * should divide it by to get VCLK */ | 610 | * should divide it by to get VCLK */ |
636 | switch (freq) { | 611 | switch (freq) { |
637 | case 24751 ... 25249: | 612 | case 24751 ... 25249: |
638 | *div = 2; | 613 | *div = 2; |
639 | DPRINTK ("Using VCLK = MCLK/2\n"); | 614 | DPRINTK("Using VCLK = MCLK/2\n"); |
640 | break; | 615 | break; |
641 | case 49501 ... 50499: | 616 | case 49501 ... 50499: |
642 | *div = 1; | 617 | *div = 1; |
643 | DPRINTK ("Using VCLK = MCLK\n"); | 618 | DPRINTK("Using VCLK = MCLK\n"); |
644 | break; | 619 | break; |
645 | default: | 620 | default: |
646 | *div = 0; | 621 | *div = 0; |
@@ -653,7 +628,6 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div) | |||
653 | static int cirrusfb_check_var(struct fb_var_screeninfo *var, | 628 | static int cirrusfb_check_var(struct fb_var_screeninfo *var, |
654 | struct fb_info *info) | 629 | struct fb_info *info) |
655 | { | 630 | { |
656 | struct cirrusfb_info *cinfo = info->par; | ||
657 | int nom, den; /* translyting from pixels->bytes */ | 631 | int nom, den; /* translyting from pixels->bytes */ |
658 | int yres, i; | 632 | int yres, i; |
659 | static struct { int xres, yres; } modes[] = | 633 | static struct { int xres, yres; } modes[] = |
@@ -665,63 +639,55 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
665 | { -1, -1 } }; | 639 | { -1, -1 } }; |
666 | 640 | ||
667 | switch (var->bits_per_pixel) { | 641 | switch (var->bits_per_pixel) { |
668 | case 0 ... 1: | 642 | case 1: |
669 | var->bits_per_pixel = 1; | ||
670 | nom = 4; | 643 | nom = 4; |
671 | den = 8; | 644 | den = 8; |
672 | break; /* 8 pixel per byte, only 1/4th of mem usable */ | 645 | break; /* 8 pixel per byte, only 1/4th of mem usable */ |
673 | case 2 ... 8: | 646 | case 8: |
674 | var->bits_per_pixel = 8; | 647 | case 16: |
675 | nom = 1; | 648 | case 24: |
649 | case 32: | ||
650 | nom = var->bits_per_pixel / 8; | ||
676 | den = 1; | 651 | den = 1; |
677 | break; /* 1 pixel == 1 byte */ | 652 | break; /* 1 pixel == 1 byte */ |
678 | case 9 ... 16: | ||
679 | var->bits_per_pixel = 16; | ||
680 | nom = 2; | ||
681 | den = 1; | ||
682 | break; /* 2 bytes per pixel */ | ||
683 | case 17 ... 24: | ||
684 | var->bits_per_pixel = 24; | ||
685 | nom = 3; | ||
686 | den = 1; | ||
687 | break; /* 3 bytes per pixel */ | ||
688 | case 25 ... 32: | ||
689 | var->bits_per_pixel = 32; | ||
690 | nom = 4; | ||
691 | den = 1; | ||
692 | break; /* 4 bytes per pixel */ | ||
693 | default: | 653 | default: |
694 | printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n", | 654 | printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." |
655 | "color depth not supported.\n", | ||
695 | var->xres, var->yres, var->bits_per_pixel); | 656 | var->xres, var->yres, var->bits_per_pixel); |
696 | DPRINTK ("EXIT - EINVAL error\n"); | 657 | DPRINTK("EXIT - EINVAL error\n"); |
697 | return -EINVAL; | 658 | return -EINVAL; |
698 | } | 659 | } |
699 | 660 | ||
700 | if (var->xres * nom / den * var->yres > cinfo->size) { | 661 | if (var->xres * nom / den * var->yres > info->screen_size) { |
701 | printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", | 662 | printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." |
663 | "resolution too high to fit into video memory!\n", | ||
702 | var->xres, var->yres, var->bits_per_pixel); | 664 | var->xres, var->yres, var->bits_per_pixel); |
703 | DPRINTK ("EXIT - EINVAL error\n"); | 665 | DPRINTK("EXIT - EINVAL error\n"); |
704 | return -EINVAL; | 666 | return -EINVAL; |
705 | } | 667 | } |
706 | 668 | ||
707 | /* use highest possible virtual resolution */ | 669 | /* use highest possible virtual resolution */ |
708 | if (var->xres_virtual == -1 && | 670 | if (var->xres_virtual == -1 && |
709 | var->yres_virtual == -1) { | 671 | var->yres_virtual == -1) { |
710 | printk ("cirrusfb: using maximum available virtual resolution\n"); | 672 | printk(KERN_INFO |
673 | "cirrusfb: using maximum available virtual resolution\n"); | ||
711 | for (i = 0; modes[i].xres != -1; i++) { | 674 | for (i = 0; modes[i].xres != -1; i++) { |
712 | if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2) | 675 | int size = modes[i].xres * nom / den * modes[i].yres; |
676 | if (size < info->screen_size / 2) | ||
713 | break; | 677 | break; |
714 | } | 678 | } |
715 | if (modes[i].xres == -1) { | 679 | if (modes[i].xres == -1) { |
716 | printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n"); | 680 | printk(KERN_ERR "cirrusfb: could not find a virtual " |
717 | DPRINTK ("EXIT - EINVAL error\n"); | 681 | "resolution that fits into video memory!!\n"); |
682 | DPRINTK("EXIT - EINVAL error\n"); | ||
718 | return -EINVAL; | 683 | return -EINVAL; |
719 | } | 684 | } |
720 | var->xres_virtual = modes[i].xres; | 685 | var->xres_virtual = modes[i].xres; |
721 | var->yres_virtual = modes[i].yres; | 686 | var->yres_virtual = modes[i].yres; |
722 | 687 | ||
723 | printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n", | 688 | printk(KERN_INFO "cirrusfb: virtual resolution set to " |
724 | var->xres_virtual, var->yres_virtual); | 689 | "maximum of %dx%d\n", var->xres_virtual, |
690 | var->yres_virtual); | ||
725 | } | 691 | } |
726 | 692 | ||
727 | if (var->xres_virtual < var->xres) | 693 | if (var->xres_virtual < var->xres) |
@@ -744,23 +710,19 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
744 | case 1: | 710 | case 1: |
745 | var->red.offset = 0; | 711 | var->red.offset = 0; |
746 | var->red.length = 1; | 712 | var->red.length = 1; |
747 | var->green.offset = 0; | 713 | var->green = var->red; |
748 | var->green.length = 1; | 714 | var->blue = var->red; |
749 | var->blue.offset = 0; | ||
750 | var->blue.length = 1; | ||
751 | break; | 715 | break; |
752 | 716 | ||
753 | case 8: | 717 | case 8: |
754 | var->red.offset = 0; | 718 | var->red.offset = 0; |
755 | var->red.length = 6; | 719 | var->red.length = 6; |
756 | var->green.offset = 0; | 720 | var->green = var->red; |
757 | var->green.length = 6; | 721 | var->blue = var->red; |
758 | var->blue.offset = 0; | ||
759 | var->blue.length = 6; | ||
760 | break; | 722 | break; |
761 | 723 | ||
762 | case 16: | 724 | case 16: |
763 | if(isPReP) { | 725 | if (isPReP) { |
764 | var->red.offset = 2; | 726 | var->red.offset = 2; |
765 | var->green.offset = -3; | 727 | var->green.offset = -3; |
766 | var->blue.offset = 8; | 728 | var->blue.offset = 8; |
@@ -775,22 +737,8 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
775 | break; | 737 | break; |
776 | 738 | ||
777 | case 24: | 739 | case 24: |
778 | if(isPReP) { | ||
779 | var->red.offset = 8; | ||
780 | var->green.offset = 16; | ||
781 | var->blue.offset = 24; | ||
782 | } else { | ||
783 | var->red.offset = 16; | ||
784 | var->green.offset = 8; | ||
785 | var->blue.offset = 0; | ||
786 | } | ||
787 | var->red.length = 8; | ||
788 | var->green.length = 8; | ||
789 | var->blue.length = 8; | ||
790 | break; | ||
791 | |||
792 | case 32: | 740 | case 32: |
793 | if(isPReP) { | 741 | if (isPReP) { |
794 | var->red.offset = 8; | 742 | var->red.offset = 8; |
795 | var->green.offset = 16; | 743 | var->green.offset = 16; |
796 | var->blue.offset = 24; | 744 | var->blue.offset = 24; |
@@ -825,54 +773,42 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
825 | yres = (yres + 1) / 2; | 773 | yres = (yres + 1) / 2; |
826 | 774 | ||
827 | if (yres >= 1280) { | 775 | if (yres >= 1280) { |
828 | printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n"); | 776 | printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; " |
829 | DPRINTK ("EXIT - EINVAL error\n"); | 777 | "special treatment required! (TODO)\n"); |
778 | DPRINTK("EXIT - EINVAL error\n"); | ||
830 | return -EINVAL; | 779 | return -EINVAL; |
831 | } | 780 | } |
832 | 781 | ||
833 | return 0; | 782 | return 0; |
834 | } | 783 | } |
835 | 784 | ||
836 | static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | 785 | static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, |
837 | struct cirrusfb_regs *regs, | 786 | struct cirrusfb_regs *regs, |
838 | const struct fb_info *info) | 787 | struct fb_info *info) |
839 | { | 788 | { |
840 | long freq; | 789 | long freq; |
841 | long maxclock; | 790 | long maxclock; |
842 | int maxclockidx = 0; | 791 | int maxclockidx = var->bits_per_pixel >> 3; |
843 | struct cirrusfb_info *cinfo = info->par; | 792 | struct cirrusfb_info *cinfo = info->par; |
844 | int xres, hfront, hsync, hback; | 793 | int xres, hfront, hsync, hback; |
845 | int yres, vfront, vsync, vback; | 794 | int yres, vfront, vsync, vback; |
846 | 795 | ||
847 | switch(var->bits_per_pixel) { | 796 | switch (var->bits_per_pixel) { |
848 | case 1: | 797 | case 1: |
849 | regs->line_length = var->xres_virtual / 8; | 798 | info->fix.line_length = var->xres_virtual / 8; |
850 | regs->visual = FB_VISUAL_MONO10; | 799 | info->fix.visual = FB_VISUAL_MONO10; |
851 | maxclockidx = 0; | ||
852 | break; | 800 | break; |
853 | 801 | ||
854 | case 8: | 802 | case 8: |
855 | regs->line_length = var->xres_virtual; | 803 | info->fix.line_length = var->xres_virtual; |
856 | regs->visual = FB_VISUAL_PSEUDOCOLOR; | 804 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
857 | maxclockidx = 1; | ||
858 | break; | 805 | break; |
859 | 806 | ||
860 | case 16: | 807 | case 16: |
861 | regs->line_length = var->xres_virtual * 2; | ||
862 | regs->visual = FB_VISUAL_DIRECTCOLOR; | ||
863 | maxclockidx = 2; | ||
864 | break; | ||
865 | |||
866 | case 24: | 808 | case 24: |
867 | regs->line_length = var->xres_virtual * 3; | ||
868 | regs->visual = FB_VISUAL_DIRECTCOLOR; | ||
869 | maxclockidx = 3; | ||
870 | break; | ||
871 | |||
872 | case 32: | 809 | case 32: |
873 | regs->line_length = var->xres_virtual * 4; | 810 | info->fix.line_length = var->xres_virtual * maxclockidx; |
874 | regs->visual = FB_VISUAL_DIRECTCOLOR; | 811 | info->fix.visual = FB_VISUAL_DIRECTCOLOR; |
875 | maxclockidx = 4; | ||
876 | break; | 812 | break; |
877 | 813 | ||
878 | default: | 814 | default: |
@@ -882,12 +818,12 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | |||
882 | break; | 818 | break; |
883 | } | 819 | } |
884 | 820 | ||
885 | regs->type = FB_TYPE_PACKED_PIXELS; | 821 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
886 | 822 | ||
887 | /* convert from ps to kHz */ | 823 | /* convert from ps to kHz */ |
888 | freq = 1000000000 / var->pixclock; | 824 | freq = PICOS2KHZ(var->pixclock); |
889 | 825 | ||
890 | DPRINTK ("desired pixclock: %ld kHz\n", freq); | 826 | DPRINTK("desired pixclock: %ld kHz\n", freq); |
891 | 827 | ||
892 | maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; | 828 | maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; |
893 | regs->multiplexing = 0; | 829 | regs->multiplexing = 0; |
@@ -902,8 +838,9 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | |||
902 | break; | 838 | break; |
903 | 839 | ||
904 | default: | 840 | default: |
905 | printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock); | 841 | printk(KERN_ERR "cirrusfb: Frequency greater " |
906 | DPRINTK ("EXIT - return -EINVAL\n"); | 842 | "than maxclock (%ld kHz)\n", maxclock); |
843 | DPRINTK("EXIT - return -EINVAL\n"); | ||
907 | return -EINVAL; | 844 | return -EINVAL; |
908 | } | 845 | } |
909 | } | 846 | } |
@@ -914,14 +851,16 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | |||
914 | case 16: | 851 | case 16: |
915 | case 32: | 852 | case 32: |
916 | if (regs->HorizRes <= 800) | 853 | if (regs->HorizRes <= 800) |
917 | freq /= 2; /* Xbh has this type of clock for 32-bit */ | 854 | /* Xbh has this type of clock for 32-bit */ |
855 | freq /= 2; | ||
918 | break; | 856 | break; |
919 | } | 857 | } |
920 | #endif | 858 | #endif |
921 | 859 | ||
922 | bestclock (freq, ®s->freq, ®s->nom, ®s->den, ®s->div, | 860 | bestclock(freq, ®s->freq, ®s->nom, ®s->den, ®s->div, |
923 | maxclock); | 861 | maxclock); |
924 | regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, ®s->divMCLK); | 862 | regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel, |
863 | ®s->divMCLK); | ||
925 | 864 | ||
926 | xres = var->xres; | 865 | xres = var->xres; |
927 | hfront = var->right_margin; | 866 | hfront = var->right_margin; |
@@ -948,7 +887,8 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | |||
948 | regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5; | 887 | regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5; |
949 | regs->HorizDispEnd = xres / 8 - 1; | 888 | regs->HorizDispEnd = xres / 8 - 1; |
950 | regs->HorizBlankStart = xres / 8; | 889 | regs->HorizBlankStart = xres / 8; |
951 | regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */ | 890 | /* does not count with "-5" */ |
891 | regs->HorizBlankEnd = regs->HorizTotal + 5; | ||
952 | regs->HorizSyncStart = (xres + hfront) / 8 + 1; | 892 | regs->HorizSyncStart = (xres + hfront) / 8 + 1; |
953 | regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1; | 893 | regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1; |
954 | 894 | ||
@@ -976,23 +916,23 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, | |||
976 | return 0; | 916 | return 0; |
977 | } | 917 | } |
978 | 918 | ||
979 | 919 | static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val, | |
980 | static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div) | 920 | int div) |
981 | { | 921 | { |
982 | assert (cinfo != NULL); | 922 | assert(cinfo != NULL); |
983 | 923 | ||
984 | if (div == 2) { | 924 | if (div == 2) { |
985 | /* VCLK = MCLK/2 */ | 925 | /* VCLK = MCLK/2 */ |
986 | unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); | 926 | unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); |
987 | vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1); | 927 | vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1); |
988 | vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); | 928 | vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); |
989 | } else if (div == 1) { | 929 | } else if (div == 1) { |
990 | /* VCLK = MCLK */ | 930 | /* VCLK = MCLK */ |
991 | unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); | 931 | unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); |
992 | vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1); | 932 | vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1); |
993 | vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); | 933 | vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); |
994 | } else { | 934 | } else { |
995 | vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f); | 935 | vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f); |
996 | } | 936 | } |
997 | } | 937 | } |
998 | 938 | ||
@@ -1001,7 +941,7 @@ static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int d | |||
1001 | 941 | ||
1002 | actually writes the values for a new video mode into the hardware, | 942 | actually writes the values for a new video mode into the hardware, |
1003 | **************************************************************************/ | 943 | **************************************************************************/ |
1004 | static int cirrusfb_set_par_foo (struct fb_info *info) | 944 | static int cirrusfb_set_par_foo(struct fb_info *info) |
1005 | { | 945 | { |
1006 | struct cirrusfb_info *cinfo = info->par; | 946 | struct cirrusfb_info *cinfo = info->par; |
1007 | struct fb_var_screeninfo *var = &info->var; | 947 | struct fb_var_screeninfo *var = &info->var; |
@@ -1011,15 +951,15 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1011 | int offset = 0, err; | 951 | int offset = 0, err; |
1012 | const struct cirrusfb_board_info_rec *bi; | 952 | const struct cirrusfb_board_info_rec *bi; |
1013 | 953 | ||
1014 | DPRINTK ("ENTER\n"); | 954 | DPRINTK("ENTER\n"); |
1015 | DPRINTK ("Requested mode: %dx%dx%d\n", | 955 | DPRINTK("Requested mode: %dx%dx%d\n", |
1016 | var->xres, var->yres, var->bits_per_pixel); | 956 | var->xres, var->yres, var->bits_per_pixel); |
1017 | DPRINTK ("pixclock: %d\n", var->pixclock); | 957 | DPRINTK("pixclock: %d\n", var->pixclock); |
1018 | 958 | ||
1019 | init_vgachip (cinfo); | 959 | init_vgachip(info); |
1020 | 960 | ||
1021 | err = cirrusfb_decode_var(var, ®s, info); | 961 | err = cirrusfb_decode_var(var, ®s, info); |
1022 | if(err) { | 962 | if (err) { |
1023 | /* should never happen */ | 963 | /* should never happen */ |
1024 | DPRINTK("mode change aborted. invalid var.\n"); | 964 | DPRINTK("mode change aborted. invalid var.\n"); |
1025 | return -EINVAL; | 965 | return -EINVAL; |
@@ -1027,34 +967,35 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1027 | 967 | ||
1028 | bi = &cirrusfb_board_info[cinfo->btype]; | 968 | bi = &cirrusfb_board_info[cinfo->btype]; |
1029 | 969 | ||
1030 | |||
1031 | /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ | 970 | /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ |
1032 | vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ | 971 | vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ |
1033 | 972 | ||
1034 | /* if debugging is enabled, all parameters get output before writing */ | 973 | /* if debugging is enabled, all parameters get output before writing */ |
1035 | DPRINTK ("CRT0: %ld\n", regs.HorizTotal); | 974 | DPRINTK("CRT0: %ld\n", regs.HorizTotal); |
1036 | vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); | 975 | vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); |
1037 | 976 | ||
1038 | DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd); | 977 | DPRINTK("CRT1: %ld\n", regs.HorizDispEnd); |
1039 | vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); | 978 | vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); |
1040 | 979 | ||
1041 | DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart); | 980 | DPRINTK("CRT2: %ld\n", regs.HorizBlankStart); |
1042 | vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); | 981 | vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); |
1043 | 982 | ||
1044 | DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */ | 983 | /* + 128: Compatible read */ |
1045 | vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32)); | 984 | DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); |
985 | vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, | ||
986 | 128 + (regs.HorizBlankEnd % 32)); | ||
1046 | 987 | ||
1047 | DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart); | 988 | DPRINTK("CRT4: %ld\n", regs.HorizSyncStart); |
1048 | vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); | 989 | vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); |
1049 | 990 | ||
1050 | tmp = regs.HorizSyncEnd % 32; | 991 | tmp = regs.HorizSyncEnd % 32; |
1051 | if (regs.HorizBlankEnd & 32) | 992 | if (regs.HorizBlankEnd & 32) |
1052 | tmp += 128; | 993 | tmp += 128; |
1053 | DPRINTK ("CRT5: %d\n", tmp); | 994 | DPRINTK("CRT5: %d\n", tmp); |
1054 | vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp); | 995 | vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); |
1055 | 996 | ||
1056 | DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff); | 997 | DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff); |
1057 | vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); | 998 | vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); |
1058 | 999 | ||
1059 | tmp = 16; /* LineCompare bit #9 */ | 1000 | tmp = 16; /* LineCompare bit #9 */ |
1060 | if (regs.VertTotal & 256) | 1001 | if (regs.VertTotal & 256) |
@@ -1071,34 +1012,34 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1071 | tmp |= 64; | 1012 | tmp |= 64; |
1072 | if (regs.VertSyncStart & 512) | 1013 | if (regs.VertSyncStart & 512) |
1073 | tmp |= 128; | 1014 | tmp |= 128; |
1074 | DPRINTK ("CRT7: %d\n", tmp); | 1015 | DPRINTK("CRT7: %d\n", tmp); |
1075 | vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp); | 1016 | vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); |
1076 | 1017 | ||
1077 | tmp = 0x40; /* LineCompare bit #8 */ | 1018 | tmp = 0x40; /* LineCompare bit #8 */ |
1078 | if (regs.VertBlankStart & 512) | 1019 | if (regs.VertBlankStart & 512) |
1079 | tmp |= 0x20; | 1020 | tmp |= 0x20; |
1080 | if (var->vmode & FB_VMODE_DOUBLE) | 1021 | if (var->vmode & FB_VMODE_DOUBLE) |
1081 | tmp |= 0x80; | 1022 | tmp |= 0x80; |
1082 | DPRINTK ("CRT9: %d\n", tmp); | 1023 | DPRINTK("CRT9: %d\n", tmp); |
1083 | vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp); | 1024 | vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); |
1084 | 1025 | ||
1085 | DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff); | 1026 | DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff); |
1086 | vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff)); | 1027 | vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff); |
1087 | 1028 | ||
1088 | DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); | 1029 | DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); |
1089 | vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32)); | 1030 | vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32); |
1090 | 1031 | ||
1091 | DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff); | 1032 | DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff); |
1092 | vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff)); | 1033 | vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff); |
1093 | 1034 | ||
1094 | DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff); | 1035 | DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff); |
1095 | vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff)); | 1036 | vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff); |
1096 | 1037 | ||
1097 | DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff); | 1038 | DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff); |
1098 | vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff)); | 1039 | vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff); |
1099 | 1040 | ||
1100 | DPRINTK ("CRT18: 0xff\n"); | 1041 | DPRINTK("CRT18: 0xff\n"); |
1101 | vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff); | 1042 | vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); |
1102 | 1043 | ||
1103 | tmp = 0; | 1044 | tmp = 0; |
1104 | if (var->vmode & FB_VMODE_INTERLACED) | 1045 | if (var->vmode & FB_VMODE_INTERLACED) |
@@ -1112,57 +1053,63 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1112 | if (regs.VertBlankEnd & 512) | 1053 | if (regs.VertBlankEnd & 512) |
1113 | tmp |= 128; | 1054 | tmp |= 128; |
1114 | 1055 | ||
1115 | DPRINTK ("CRT1a: %d\n", tmp); | 1056 | DPRINTK("CRT1a: %d\n", tmp); |
1116 | vga_wcrt (regbase, CL_CRT1A, tmp); | 1057 | vga_wcrt(regbase, CL_CRT1A, tmp); |
1117 | 1058 | ||
1118 | /* set VCLK0 */ | 1059 | /* set VCLK0 */ |
1119 | /* hardware RefClock: 14.31818 MHz */ | 1060 | /* hardware RefClock: 14.31818 MHz */ |
1120 | /* formula: VClk = (OSC * N) / (D * (1+P)) */ | 1061 | /* formula: VClk = (OSC * N) / (D * (1+P)) */ |
1121 | /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ | 1062 | /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ |
1122 | 1063 | ||
1123 | vga_wseq (regbase, CL_SEQRB, regs.nom); | 1064 | vga_wseq(regbase, CL_SEQRB, regs.nom); |
1124 | tmp = regs.den << 1; | 1065 | tmp = regs.den << 1; |
1125 | if (regs.div != 0) | 1066 | if (regs.div != 0) |
1126 | tmp |= 1; | 1067 | tmp |= 1; |
1127 | 1068 | ||
1069 | /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ | ||
1128 | if ((cinfo->btype == BT_SD64) || | 1070 | if ((cinfo->btype == BT_SD64) || |
1129 | (cinfo->btype == BT_ALPINE) || | 1071 | (cinfo->btype == BT_ALPINE) || |
1130 | (cinfo->btype == BT_GD5480)) | 1072 | (cinfo->btype == BT_GD5480)) |
1131 | tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ | 1073 | tmp |= 0x80; |
1132 | 1074 | ||
1133 | DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp); | 1075 | DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); |
1134 | vga_wseq (regbase, CL_SEQR1B, tmp); | 1076 | vga_wseq(regbase, CL_SEQR1B, tmp); |
1135 | 1077 | ||
1136 | if (regs.VertRes >= 1024) | 1078 | if (regs.VertRes >= 1024) |
1137 | /* 1280x1024 */ | 1079 | /* 1280x1024 */ |
1138 | vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7); | 1080 | vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7); |
1139 | else | 1081 | else |
1140 | /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit | 1082 | /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit |
1141 | * address wrap, no compat. */ | 1083 | * address wrap, no compat. */ |
1142 | vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3); | 1084 | vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); |
1143 | 1085 | ||
1144 | /* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ | 1086 | /* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); |
1087 | * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ | ||
1145 | 1088 | ||
1146 | /* don't know if it would hurt to also program this if no interlaced */ | 1089 | /* don't know if it would hurt to also program this if no interlaced */ |
1147 | /* mode is used, but I feel better this way.. :-) */ | 1090 | /* mode is used, but I feel better this way.. :-) */ |
1148 | if (var->vmode & FB_VMODE_INTERLACED) | 1091 | if (var->vmode & FB_VMODE_INTERLACED) |
1149 | vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); | 1092 | vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); |
1150 | else | 1093 | else |
1151 | vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ | 1094 | vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ |
1152 | 1095 | ||
1153 | vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0); | 1096 | vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); |
1154 | 1097 | ||
1155 | /* adjust horizontal/vertical sync type (low/high) */ | 1098 | /* adjust horizontal/vertical sync type (low/high) */ |
1156 | tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */ | 1099 | /* enable display memory & CRTC I/O address for color mode */ |
1100 | tmp = 0x03; | ||
1157 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | 1101 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) |
1158 | tmp |= 0x40; | 1102 | tmp |= 0x40; |
1159 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | 1103 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) |
1160 | tmp |= 0x80; | 1104 | tmp |= 0x80; |
1161 | WGen (cinfo, VGA_MIS_W, tmp); | 1105 | WGen(cinfo, VGA_MIS_W, tmp); |
1162 | 1106 | ||
1163 | vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */ | 1107 | /* Screen A Preset Row-Scan register */ |
1164 | vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */ | 1108 | vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); |
1165 | vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */ | 1109 | /* text cursor on and start line */ |
1110 | vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); | ||
1111 | /* text cursor end line */ | ||
1112 | vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31); | ||
1166 | 1113 | ||
1167 | /****************************************************** | 1114 | /****************************************************** |
1168 | * | 1115 | * |
@@ -1172,8 +1119,8 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1172 | 1119 | ||
1173 | /* programming for different color depths */ | 1120 | /* programming for different color depths */ |
1174 | if (var->bits_per_pixel == 1) { | 1121 | if (var->bits_per_pixel == 1) { |
1175 | DPRINTK ("cirrusfb: preparing for 1 bit deep display\n"); | 1122 | DPRINTK("cirrusfb: preparing for 1 bit deep display\n"); |
1176 | vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */ | 1123 | vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */ |
1177 | 1124 | ||
1178 | /* SR07 */ | 1125 | /* SR07 */ |
1179 | switch (cinfo->btype) { | 1126 | switch (cinfo->btype) { |
@@ -1184,71 +1131,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1184 | case BT_PICASSO4: | 1131 | case BT_PICASSO4: |
1185 | case BT_ALPINE: | 1132 | case BT_ALPINE: |
1186 | case BT_GD5480: | 1133 | case BT_GD5480: |
1187 | DPRINTK (" (for GD54xx)\n"); | 1134 | DPRINTK(" (for GD54xx)\n"); |
1188 | vga_wseq (regbase, CL_SEQR7, | 1135 | vga_wseq(regbase, CL_SEQR7, |
1189 | regs.multiplexing ? | 1136 | regs.multiplexing ? |
1190 | bi->sr07_1bpp_mux : bi->sr07_1bpp); | 1137 | bi->sr07_1bpp_mux : bi->sr07_1bpp); |
1191 | break; | 1138 | break; |
1192 | 1139 | ||
1193 | case BT_LAGUNA: | 1140 | case BT_LAGUNA: |
1194 | DPRINTK (" (for GD546x)\n"); | 1141 | DPRINTK(" (for GD546x)\n"); |
1195 | vga_wseq (regbase, CL_SEQR7, | 1142 | vga_wseq(regbase, CL_SEQR7, |
1196 | vga_rseq (regbase, CL_SEQR7) & ~0x01); | 1143 | vga_rseq(regbase, CL_SEQR7) & ~0x01); |
1197 | break; | 1144 | break; |
1198 | 1145 | ||
1199 | default: | 1146 | default: |
1200 | printk (KERN_WARNING "cirrusfb: unknown Board\n"); | 1147 | printk(KERN_WARNING "cirrusfb: unknown Board\n"); |
1201 | break; | 1148 | break; |
1202 | } | 1149 | } |
1203 | 1150 | ||
1204 | /* Extended Sequencer Mode */ | 1151 | /* Extended Sequencer Mode */ |
1205 | switch (cinfo->btype) { | 1152 | switch (cinfo->btype) { |
1206 | case BT_SD64: | 1153 | case BT_SD64: |
1207 | /* setting the SEQRF on SD64 is not necessary (only during init) */ | 1154 | /* setting the SEQRF on SD64 is not necessary |
1208 | DPRINTK ("(for SD64)\n"); | 1155 | * (only during init) |
1209 | vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */ | 1156 | */ |
1157 | DPRINTK("(for SD64)\n"); | ||
1158 | /* MCLK select */ | ||
1159 | vga_wseq(regbase, CL_SEQR1F, 0x1a); | ||
1210 | break; | 1160 | break; |
1211 | 1161 | ||
1212 | case BT_PICCOLO: | 1162 | case BT_PICCOLO: |
1213 | DPRINTK ("(for Piccolo)\n"); | 1163 | case BT_SPECTRUM: |
1214 | /* ### ueberall 0x22? */ | 1164 | DPRINTK("(for Piccolo/Spectrum)\n"); |
1215 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ | 1165 | /* ### ueberall 0x22? */ |
1216 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ | 1166 | /* ##vorher 1c MCLK select */ |
1167 | vga_wseq(regbase, CL_SEQR1F, 0x22); | ||
1168 | /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ | ||
1169 | vga_wseq(regbase, CL_SEQRF, 0xb0); | ||
1217 | break; | 1170 | break; |
1218 | 1171 | ||
1219 | case BT_PICASSO: | 1172 | case BT_PICASSO: |
1220 | DPRINTK ("(for Picasso)\n"); | 1173 | DPRINTK("(for Picasso)\n"); |
1221 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */ | 1174 | /* ##vorher 22 MCLK select */ |
1222 | vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */ | 1175 | vga_wseq(regbase, CL_SEQR1F, 0x22); |
1223 | break; | 1176 | /* ## vorher d0 avoid FIFO underruns..? */ |
1224 | 1177 | vga_wseq(regbase, CL_SEQRF, 0xd0); | |
1225 | case BT_SPECTRUM: | ||
1226 | DPRINTK ("(for Spectrum)\n"); | ||
1227 | /* ### ueberall 0x22? */ | ||
1228 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ | ||
1229 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */ | ||
1230 | break; | 1178 | break; |
1231 | 1179 | ||
1232 | case BT_PICASSO4: | 1180 | case BT_PICASSO4: |
1233 | case BT_ALPINE: | 1181 | case BT_ALPINE: |
1234 | case BT_GD5480: | 1182 | case BT_GD5480: |
1235 | case BT_LAGUNA: | 1183 | case BT_LAGUNA: |
1236 | DPRINTK (" (for GD54xx)\n"); | 1184 | DPRINTK(" (for GD54xx)\n"); |
1237 | /* do nothing */ | 1185 | /* do nothing */ |
1238 | break; | 1186 | break; |
1239 | 1187 | ||
1240 | default: | 1188 | default: |
1241 | printk (KERN_WARNING "cirrusfb: unknown Board\n"); | 1189 | printk(KERN_WARNING "cirrusfb: unknown Board\n"); |
1242 | break; | 1190 | break; |
1243 | } | 1191 | } |
1244 | 1192 | ||
1245 | WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */ | 1193 | /* pixel mask: pass-through for first plane */ |
1194 | WGen(cinfo, VGA_PEL_MSK, 0x01); | ||
1246 | if (regs.multiplexing) | 1195 | if (regs.multiplexing) |
1247 | WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ | 1196 | /* hidden dac reg: 1280x1024 */ |
1197 | WHDR(cinfo, 0x4a); | ||
1248 | else | 1198 | else |
1249 | WHDR (cinfo, 0); /* hidden dac: nothing */ | 1199 | /* hidden dac: nothing */ |
1250 | vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */ | 1200 | WHDR(cinfo, 0); |
1251 | vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */ | 1201 | /* memory mode: odd/even, ext. memory */ |
1202 | vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06); | ||
1203 | /* plane mask: only write to first plane */ | ||
1204 | vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01); | ||
1252 | offset = var->xres_virtual / 16; | 1205 | offset = var->xres_virtual / 16; |
1253 | } | 1206 | } |
1254 | 1207 | ||
@@ -1259,7 +1212,7 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1259 | */ | 1212 | */ |
1260 | 1213 | ||
1261 | else if (var->bits_per_pixel == 8) { | 1214 | else if (var->bits_per_pixel == 8) { |
1262 | DPRINTK ("cirrusfb: preparing for 8 bit deep display\n"); | 1215 | DPRINTK("cirrusfb: preparing for 8 bit deep display\n"); |
1263 | switch (cinfo->btype) { | 1216 | switch (cinfo->btype) { |
1264 | case BT_SD64: | 1217 | case BT_SD64: |
1265 | case BT_PICCOLO: | 1218 | case BT_PICCOLO: |
@@ -1268,75 +1221,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1268 | case BT_PICASSO4: | 1221 | case BT_PICASSO4: |
1269 | case BT_ALPINE: | 1222 | case BT_ALPINE: |
1270 | case BT_GD5480: | 1223 | case BT_GD5480: |
1271 | DPRINTK (" (for GD54xx)\n"); | 1224 | DPRINTK(" (for GD54xx)\n"); |
1272 | vga_wseq (regbase, CL_SEQR7, | 1225 | vga_wseq(regbase, CL_SEQR7, |
1273 | regs.multiplexing ? | 1226 | regs.multiplexing ? |
1274 | bi->sr07_8bpp_mux : bi->sr07_8bpp); | 1227 | bi->sr07_8bpp_mux : bi->sr07_8bpp); |
1275 | break; | 1228 | break; |
1276 | 1229 | ||
1277 | case BT_LAGUNA: | 1230 | case BT_LAGUNA: |
1278 | DPRINTK (" (for GD546x)\n"); | 1231 | DPRINTK(" (for GD546x)\n"); |
1279 | vga_wseq (regbase, CL_SEQR7, | 1232 | vga_wseq(regbase, CL_SEQR7, |
1280 | vga_rseq (regbase, CL_SEQR7) | 0x01); | 1233 | vga_rseq(regbase, CL_SEQR7) | 0x01); |
1281 | break; | 1234 | break; |
1282 | 1235 | ||
1283 | default: | 1236 | default: |
1284 | printk (KERN_WARNING "cirrusfb: unknown Board\n"); | 1237 | printk(KERN_WARNING "cirrusfb: unknown Board\n"); |
1285 | break; | 1238 | break; |
1286 | } | 1239 | } |
1287 | 1240 | ||
1288 | switch (cinfo->btype) { | 1241 | switch (cinfo->btype) { |
1289 | case BT_SD64: | 1242 | case BT_SD64: |
1290 | vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */ | 1243 | /* MCLK select */ |
1244 | vga_wseq(regbase, CL_SEQR1F, 0x1d); | ||
1291 | break; | 1245 | break; |
1292 | 1246 | ||
1293 | case BT_PICCOLO: | 1247 | case BT_PICCOLO: |
1294 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ | ||
1295 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | ||
1296 | break; | ||
1297 | |||
1298 | case BT_PICASSO: | 1248 | case BT_PICASSO: |
1299 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ | ||
1300 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | ||
1301 | break; | ||
1302 | |||
1303 | case BT_SPECTRUM: | 1249 | case BT_SPECTRUM: |
1304 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ | 1250 | /* ### vorher 1c MCLK select */ |
1305 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | 1251 | vga_wseq(regbase, CL_SEQR1F, 0x22); |
1252 | /* Fast Page-Mode writes */ | ||
1253 | vga_wseq(regbase, CL_SEQRF, 0xb0); | ||
1306 | break; | 1254 | break; |
1307 | 1255 | ||
1308 | case BT_PICASSO4: | 1256 | case BT_PICASSO4: |
1309 | #ifdef CONFIG_ZORRO | 1257 | #ifdef CONFIG_ZORRO |
1310 | vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */ | 1258 | /* ### INCOMPLETE!! */ |
1259 | vga_wseq(regbase, CL_SEQRF, 0xb8); | ||
1311 | #endif | 1260 | #endif |
1312 | /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ | 1261 | /* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ |
1313 | break; | 1262 | break; |
1314 | 1263 | ||
1315 | case BT_ALPINE: | 1264 | case BT_ALPINE: |
1316 | DPRINTK (" (for GD543x)\n"); | 1265 | DPRINTK(" (for GD543x)\n"); |
1317 | cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); | 1266 | cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); |
1318 | /* We already set SRF and SR1F */ | 1267 | /* We already set SRF and SR1F */ |
1319 | break; | 1268 | break; |
1320 | 1269 | ||
1321 | case BT_GD5480: | 1270 | case BT_GD5480: |
1322 | case BT_LAGUNA: | 1271 | case BT_LAGUNA: |
1323 | DPRINTK (" (for GD54xx)\n"); | 1272 | DPRINTK(" (for GD54xx)\n"); |
1324 | /* do nothing */ | 1273 | /* do nothing */ |
1325 | break; | 1274 | break; |
1326 | 1275 | ||
1327 | default: | 1276 | default: |
1328 | printk (KERN_WARNING "cirrusfb: unknown Board\n"); | 1277 | printk(KERN_WARNING "cirrusfb: unknown Board\n"); |
1329 | break; | 1278 | break; |
1330 | } | 1279 | } |
1331 | 1280 | ||
1332 | vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ | 1281 | /* mode register: 256 color mode */ |
1333 | WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ | 1282 | vga_wgfx(regbase, VGA_GFX_MODE, 64); |
1283 | /* pixel mask: pass-through all planes */ | ||
1284 | WGen(cinfo, VGA_PEL_MSK, 0xff); | ||
1334 | if (regs.multiplexing) | 1285 | if (regs.multiplexing) |
1335 | WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ | 1286 | /* hidden dac reg: 1280x1024 */ |
1287 | WHDR(cinfo, 0x4a); | ||
1336 | else | 1288 | else |
1337 | WHDR (cinfo, 0); /* hidden dac: nothing */ | 1289 | /* hidden dac: nothing */ |
1338 | vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ | 1290 | WHDR(cinfo, 0); |
1339 | vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ | 1291 | /* memory mode: chain4, ext. memory */ |
1292 | vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); | ||
1293 | /* plane mask: enable writing to all 4 planes */ | ||
1294 | vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); | ||
1340 | offset = var->xres_virtual / 8; | 1295 | offset = var->xres_virtual / 8; |
1341 | } | 1296 | } |
1342 | 1297 | ||
@@ -1347,72 +1302,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1347 | */ | 1302 | */ |
1348 | 1303 | ||
1349 | else if (var->bits_per_pixel == 16) { | 1304 | else if (var->bits_per_pixel == 16) { |
1350 | DPRINTK ("cirrusfb: preparing for 16 bit deep display\n"); | 1305 | DPRINTK("cirrusfb: preparing for 16 bit deep display\n"); |
1351 | switch (cinfo->btype) { | 1306 | switch (cinfo->btype) { |
1352 | case BT_SD64: | 1307 | case BT_SD64: |
1353 | vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */ | 1308 | /* Extended Sequencer Mode: 256c col. mode */ |
1354 | vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ | 1309 | vga_wseq(regbase, CL_SEQR7, 0xf7); |
1310 | /* MCLK select */ | ||
1311 | vga_wseq(regbase, CL_SEQR1F, 0x1e); | ||
1355 | break; | 1312 | break; |
1356 | 1313 | ||
1357 | case BT_PICCOLO: | 1314 | case BT_PICCOLO: |
1358 | vga_wseq (regbase, CL_SEQR7, 0x87); | 1315 | case BT_SPECTRUM: |
1359 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | 1316 | vga_wseq(regbase, CL_SEQR7, 0x87); |
1360 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | 1317 | /* Fast Page-Mode writes */ |
1318 | vga_wseq(regbase, CL_SEQRF, 0xb0); | ||
1319 | /* MCLK select */ | ||
1320 | vga_wseq(regbase, CL_SEQR1F, 0x22); | ||
1361 | break; | 1321 | break; |
1362 | 1322 | ||
1363 | case BT_PICASSO: | 1323 | case BT_PICASSO: |
1364 | vga_wseq (regbase, CL_SEQR7, 0x27); | 1324 | vga_wseq(regbase, CL_SEQR7, 0x27); |
1365 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | 1325 | /* Fast Page-Mode writes */ |
1366 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | 1326 | vga_wseq(regbase, CL_SEQRF, 0xb0); |
1367 | break; | 1327 | /* MCLK select */ |
1368 | 1328 | vga_wseq(regbase, CL_SEQR1F, 0x22); | |
1369 | case BT_SPECTRUM: | ||
1370 | vga_wseq (regbase, CL_SEQR7, 0x87); | ||
1371 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | ||
1372 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | ||
1373 | break; | 1329 | break; |
1374 | 1330 | ||
1375 | case BT_PICASSO4: | 1331 | case BT_PICASSO4: |
1376 | vga_wseq (regbase, CL_SEQR7, 0x27); | 1332 | vga_wseq(regbase, CL_SEQR7, 0x27); |
1377 | /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ | 1333 | /* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ |
1378 | break; | 1334 | break; |
1379 | 1335 | ||
1380 | case BT_ALPINE: | 1336 | case BT_ALPINE: |
1381 | DPRINTK (" (for GD543x)\n"); | 1337 | DPRINTK(" (for GD543x)\n"); |
1382 | if (regs.HorizRes >= 1024) | 1338 | if (regs.HorizRes >= 1024) |
1383 | vga_wseq (regbase, CL_SEQR7, 0xa7); | 1339 | vga_wseq(regbase, CL_SEQR7, 0xa7); |
1384 | else | 1340 | else |
1385 | vga_wseq (regbase, CL_SEQR7, 0xa3); | 1341 | vga_wseq(regbase, CL_SEQR7, 0xa3); |
1386 | cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); | 1342 | cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); |
1387 | break; | 1343 | break; |
1388 | 1344 | ||
1389 | case BT_GD5480: | 1345 | case BT_GD5480: |
1390 | DPRINTK (" (for GD5480)\n"); | 1346 | DPRINTK(" (for GD5480)\n"); |
1391 | vga_wseq (regbase, CL_SEQR7, 0x17); | 1347 | vga_wseq(regbase, CL_SEQR7, 0x17); |
1392 | /* We already set SRF and SR1F */ | 1348 | /* We already set SRF and SR1F */ |
1393 | break; | 1349 | break; |
1394 | 1350 | ||
1395 | case BT_LAGUNA: | 1351 | case BT_LAGUNA: |
1396 | DPRINTK (" (for GD546x)\n"); | 1352 | DPRINTK(" (for GD546x)\n"); |
1397 | vga_wseq (regbase, CL_SEQR7, | 1353 | vga_wseq(regbase, CL_SEQR7, |
1398 | vga_rseq (regbase, CL_SEQR7) & ~0x01); | 1354 | vga_rseq(regbase, CL_SEQR7) & ~0x01); |
1399 | break; | 1355 | break; |
1400 | 1356 | ||
1401 | default: | 1357 | default: |
1402 | printk (KERN_WARNING "CIRRUSFB: unknown Board\n"); | 1358 | printk(KERN_WARNING "CIRRUSFB: unknown Board\n"); |
1403 | break; | 1359 | break; |
1404 | } | 1360 | } |
1405 | 1361 | ||
1406 | vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ | 1362 | /* mode register: 256 color mode */ |
1407 | WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ | 1363 | vga_wgfx(regbase, VGA_GFX_MODE, 64); |
1364 | /* pixel mask: pass-through all planes */ | ||
1365 | WGen(cinfo, VGA_PEL_MSK, 0xff); | ||
1408 | #ifdef CONFIG_PCI | 1366 | #ifdef CONFIG_PCI |
1409 | WHDR (cinfo, 0xc0); /* Copy Xbh */ | 1367 | WHDR(cinfo, 0xc0); /* Copy Xbh */ |
1410 | #elif defined(CONFIG_ZORRO) | 1368 | #elif defined(CONFIG_ZORRO) |
1411 | /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ | 1369 | /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ |
1412 | WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */ | 1370 | WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */ |
1413 | #endif | 1371 | #endif |
1414 | vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ | 1372 | /* memory mode: chain4, ext. memory */ |
1415 | vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ | 1373 | vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); |
1374 | /* plane mask: enable writing to all 4 planes */ | ||
1375 | vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); | ||
1416 | offset = var->xres_virtual / 4; | 1376 | offset = var->xres_virtual / 4; |
1417 | } | 1377 | } |
1418 | 1378 | ||
@@ -1423,64 +1383,70 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1423 | */ | 1383 | */ |
1424 | 1384 | ||
1425 | else if (var->bits_per_pixel == 32) { | 1385 | else if (var->bits_per_pixel == 32) { |
1426 | DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n"); | 1386 | DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n"); |
1427 | switch (cinfo->btype) { | 1387 | switch (cinfo->btype) { |
1428 | case BT_SD64: | 1388 | case BT_SD64: |
1429 | vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */ | 1389 | /* Extended Sequencer Mode: 256c col. mode */ |
1430 | vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ | 1390 | vga_wseq(regbase, CL_SEQR7, 0xf9); |
1391 | /* MCLK select */ | ||
1392 | vga_wseq(regbase, CL_SEQR1F, 0x1e); | ||
1431 | break; | 1393 | break; |
1432 | 1394 | ||
1433 | case BT_PICCOLO: | 1395 | case BT_PICCOLO: |
1434 | vga_wseq (regbase, CL_SEQR7, 0x85); | 1396 | case BT_SPECTRUM: |
1435 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | 1397 | vga_wseq(regbase, CL_SEQR7, 0x85); |
1436 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | 1398 | /* Fast Page-Mode writes */ |
1399 | vga_wseq(regbase, CL_SEQRF, 0xb0); | ||
1400 | /* MCLK select */ | ||
1401 | vga_wseq(regbase, CL_SEQR1F, 0x22); | ||
1437 | break; | 1402 | break; |
1438 | 1403 | ||
1439 | case BT_PICASSO: | 1404 | case BT_PICASSO: |
1440 | vga_wseq (regbase, CL_SEQR7, 0x25); | 1405 | vga_wseq(regbase, CL_SEQR7, 0x25); |
1441 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | 1406 | /* Fast Page-Mode writes */ |
1442 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | 1407 | vga_wseq(regbase, CL_SEQRF, 0xb0); |
1443 | break; | 1408 | /* MCLK select */ |
1444 | 1409 | vga_wseq(regbase, CL_SEQR1F, 0x22); | |
1445 | case BT_SPECTRUM: | ||
1446 | vga_wseq (regbase, CL_SEQR7, 0x85); | ||
1447 | vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ | ||
1448 | vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ | ||
1449 | break; | 1410 | break; |
1450 | 1411 | ||
1451 | case BT_PICASSO4: | 1412 | case BT_PICASSO4: |
1452 | vga_wseq (regbase, CL_SEQR7, 0x25); | 1413 | vga_wseq(regbase, CL_SEQR7, 0x25); |
1453 | /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ | 1414 | /* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ |
1454 | break; | 1415 | break; |
1455 | 1416 | ||
1456 | case BT_ALPINE: | 1417 | case BT_ALPINE: |
1457 | DPRINTK (" (for GD543x)\n"); | 1418 | DPRINTK(" (for GD543x)\n"); |
1458 | vga_wseq (regbase, CL_SEQR7, 0xa9); | 1419 | vga_wseq(regbase, CL_SEQR7, 0xa9); |
1459 | cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); | 1420 | cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); |
1460 | break; | 1421 | break; |
1461 | 1422 | ||
1462 | case BT_GD5480: | 1423 | case BT_GD5480: |
1463 | DPRINTK (" (for GD5480)\n"); | 1424 | DPRINTK(" (for GD5480)\n"); |
1464 | vga_wseq (regbase, CL_SEQR7, 0x19); | 1425 | vga_wseq(regbase, CL_SEQR7, 0x19); |
1465 | /* We already set SRF and SR1F */ | 1426 | /* We already set SRF and SR1F */ |
1466 | break; | 1427 | break; |
1467 | 1428 | ||
1468 | case BT_LAGUNA: | 1429 | case BT_LAGUNA: |
1469 | DPRINTK (" (for GD546x)\n"); | 1430 | DPRINTK(" (for GD546x)\n"); |
1470 | vga_wseq (regbase, CL_SEQR7, | 1431 | vga_wseq(regbase, CL_SEQR7, |
1471 | vga_rseq (regbase, CL_SEQR7) & ~0x01); | 1432 | vga_rseq(regbase, CL_SEQR7) & ~0x01); |
1472 | break; | 1433 | break; |
1473 | 1434 | ||
1474 | default: | 1435 | default: |
1475 | printk (KERN_WARNING "cirrusfb: unknown Board\n"); | 1436 | printk(KERN_WARNING "cirrusfb: unknown Board\n"); |
1476 | break; | 1437 | break; |
1477 | } | 1438 | } |
1478 | 1439 | ||
1479 | vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ | 1440 | /* mode register: 256 color mode */ |
1480 | WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ | 1441 | vga_wgfx(regbase, VGA_GFX_MODE, 64); |
1481 | WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */ | 1442 | /* pixel mask: pass-through all planes */ |
1482 | vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ | 1443 | WGen(cinfo, VGA_PEL_MSK, 0xff); |
1483 | vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ | 1444 | /* hidden dac reg: 8-8-8 mode (24 or 32) */ |
1445 | WHDR(cinfo, 0xc5); | ||
1446 | /* memory mode: chain4, ext. memory */ | ||
1447 | vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); | ||
1448 | /* plane mask: enable writing to all 4 planes */ | ||
1449 | vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); | ||
1484 | offset = var->xres_virtual / 4; | 1450 | offset = var->xres_virtual / 4; |
1485 | } | 1451 | } |
1486 | 1452 | ||
@@ -1490,48 +1456,67 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1490 | * | 1456 | * |
1491 | */ | 1457 | */ |
1492 | 1458 | ||
1493 | else { | 1459 | else |
1494 | printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n", | 1460 | printk(KERN_ERR "cirrusfb: What's this?? " |
1461 | " requested color depth == %d.\n", | ||
1495 | var->bits_per_pixel); | 1462 | var->bits_per_pixel); |
1496 | } | ||
1497 | 1463 | ||
1498 | vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff); | 1464 | vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff); |
1499 | tmp = 0x22; | 1465 | tmp = 0x22; |
1500 | if (offset & 0x100) | 1466 | if (offset & 0x100) |
1501 | tmp |= 0x10; /* offset overflow bit */ | 1467 | tmp |= 0x10; /* offset overflow bit */ |
1502 | 1468 | ||
1503 | vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */ | 1469 | /* screen start addr #16-18, fastpagemode cycles */ |
1470 | vga_wcrt(regbase, CL_CRT1B, tmp); | ||
1504 | 1471 | ||
1505 | if (cinfo->btype == BT_SD64 || | 1472 | if (cinfo->btype == BT_SD64 || |
1506 | cinfo->btype == BT_PICASSO4 || | 1473 | cinfo->btype == BT_PICASSO4 || |
1507 | cinfo->btype == BT_ALPINE || | 1474 | cinfo->btype == BT_ALPINE || |
1508 | cinfo->btype == BT_GD5480) | 1475 | cinfo->btype == BT_GD5480) |
1509 | vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */ | 1476 | /* screen start address bit 19 */ |
1510 | 1477 | vga_wcrt(regbase, CL_CRT1D, 0x00); | |
1511 | vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */ | 1478 | |
1512 | vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */ | 1479 | /* text cursor location high */ |
1513 | vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */ | 1480 | vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0); |
1514 | 1481 | /* text cursor location low */ | |
1515 | vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */ | 1482 | vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0); |
1516 | vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */ | 1483 | /* underline row scanline = at very bottom */ |
1517 | vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */ | 1484 | vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0); |
1518 | vga_wattr (regbase, CL_AR33, 0); /* pixel panning */ | 1485 | |
1519 | vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */ | 1486 | /* controller mode */ |
1487 | vga_wattr(regbase, VGA_ATC_MODE, 1); | ||
1488 | /* overscan (border) color */ | ||
1489 | vga_wattr(regbase, VGA_ATC_OVERSCAN, 0); | ||
1490 | /* color plane enable */ | ||
1491 | vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15); | ||
1492 | /* pixel panning */ | ||
1493 | vga_wattr(regbase, CL_AR33, 0); | ||
1494 | /* color select */ | ||
1495 | vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0); | ||
1520 | 1496 | ||
1521 | /* [ EGS: SetOffset(); ] */ | 1497 | /* [ EGS: SetOffset(); ] */ |
1522 | /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ | 1498 | /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ |
1523 | AttrOn (cinfo); | 1499 | AttrOn(cinfo); |
1524 | 1500 | ||
1525 | vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */ | 1501 | /* set/reset register */ |
1526 | vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */ | 1502 | vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0); |
1527 | vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */ | 1503 | /* set/reset enable */ |
1528 | vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */ | 1504 | vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0); |
1529 | vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */ | 1505 | /* color compare */ |
1530 | vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */ | 1506 | vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0); |
1531 | vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */ | 1507 | /* data rotate */ |
1532 | vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */ | 1508 | vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0); |
1533 | 1509 | /* read map select */ | |
1534 | vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */ | 1510 | vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0); |
1511 | /* miscellaneous register */ | ||
1512 | vga_wgfx(regbase, VGA_GFX_MISC, 1); | ||
1513 | /* color don't care */ | ||
1514 | vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15); | ||
1515 | /* bit mask */ | ||
1516 | vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255); | ||
1517 | |||
1518 | /* graphics cursor attributes: nothing special */ | ||
1519 | vga_wseq(regbase, CL_SEQR12, 0x0); | ||
1535 | 1520 | ||
1536 | /* finally, turn on everything - turn off "FullBandwidth" bit */ | 1521 | /* finally, turn on everything - turn off "FullBandwidth" bit */ |
1537 | /* also, set "DotClock%2" bit where requested */ | 1522 | /* also, set "DotClock%2" bit where requested */ |
@@ -1542,36 +1527,33 @@ static int cirrusfb_set_par_foo (struct fb_info *info) | |||
1542 | tmp |= 0x08; | 1527 | tmp |= 0x08; |
1543 | */ | 1528 | */ |
1544 | 1529 | ||
1545 | vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp); | 1530 | vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); |
1546 | DPRINTK ("CL_SEQR1: %d\n", tmp); | 1531 | DPRINTK("CL_SEQR1: %d\n", tmp); |
1547 | 1532 | ||
1548 | cinfo->currentmode = regs; | 1533 | cinfo->currentmode = regs; |
1549 | info->fix.type = regs.type; | ||
1550 | info->fix.visual = regs.visual; | ||
1551 | info->fix.line_length = regs.line_length; | ||
1552 | 1534 | ||
1553 | /* pan to requested offset */ | 1535 | /* pan to requested offset */ |
1554 | cirrusfb_pan_display (var, info); | 1536 | cirrusfb_pan_display(var, info); |
1555 | 1537 | ||
1556 | #ifdef CIRRUSFB_DEBUG | 1538 | #ifdef CIRRUSFB_DEBUG |
1557 | cirrusfb_dump (); | 1539 | cirrusfb_dump(); |
1558 | #endif | 1540 | #endif |
1559 | 1541 | ||
1560 | DPRINTK ("EXIT\n"); | 1542 | DPRINTK("EXIT\n"); |
1561 | return 0; | 1543 | return 0; |
1562 | } | 1544 | } |
1563 | 1545 | ||
1564 | /* for some reason incomprehensible to me, cirrusfb requires that you write | 1546 | /* for some reason incomprehensible to me, cirrusfb requires that you write |
1565 | * the registers twice for the settings to take..grr. -dte */ | 1547 | * the registers twice for the settings to take..grr. -dte */ |
1566 | static int cirrusfb_set_par (struct fb_info *info) | 1548 | static int cirrusfb_set_par(struct fb_info *info) |
1567 | { | 1549 | { |
1568 | cirrusfb_set_par_foo (info); | 1550 | cirrusfb_set_par_foo(info); |
1569 | return cirrusfb_set_par_foo (info); | 1551 | return cirrusfb_set_par_foo(info); |
1570 | } | 1552 | } |
1571 | 1553 | ||
1572 | static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, | 1554 | static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
1573 | unsigned blue, unsigned transp, | 1555 | unsigned blue, unsigned transp, |
1574 | struct fb_info *info) | 1556 | struct fb_info *info) |
1575 | { | 1557 | { |
1576 | struct cirrusfb_info *cinfo = info->par; | 1558 | struct cirrusfb_info *cinfo = info->par; |
1577 | 1559 | ||
@@ -1584,34 +1566,18 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, | |||
1584 | green >>= (16 - info->var.green.length); | 1566 | green >>= (16 - info->var.green.length); |
1585 | blue >>= (16 - info->var.blue.length); | 1567 | blue >>= (16 - info->var.blue.length); |
1586 | 1568 | ||
1587 | if (regno>=16) | 1569 | if (regno >= 16) |
1588 | return 1; | 1570 | return 1; |
1589 | v = (red << info->var.red.offset) | | 1571 | v = (red << info->var.red.offset) | |
1590 | (green << info->var.green.offset) | | 1572 | (green << info->var.green.offset) | |
1591 | (blue << info->var.blue.offset); | 1573 | (blue << info->var.blue.offset); |
1592 | 1574 | ||
1593 | switch (info->var.bits_per_pixel) { | 1575 | cinfo->pseudo_palette[regno] = v; |
1594 | case 8: | ||
1595 | cinfo->pseudo_palette[regno] = v; | ||
1596 | break; | ||
1597 | case 16: | ||
1598 | cinfo->pseudo_palette[regno] = v; | ||
1599 | break; | ||
1600 | case 24: | ||
1601 | case 32: | ||
1602 | cinfo->pseudo_palette[regno] = v; | ||
1603 | break; | ||
1604 | } | ||
1605 | return 0; | 1576 | return 0; |
1606 | } | 1577 | } |
1607 | 1578 | ||
1608 | cinfo->palette[regno].red = red; | 1579 | if (info->var.bits_per_pixel == 8) |
1609 | cinfo->palette[regno].green = green; | 1580 | WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10); |
1610 | cinfo->palette[regno].blue = blue; | ||
1611 | |||
1612 | if (info->var.bits_per_pixel == 8) { | ||
1613 | WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10); | ||
1614 | } | ||
1615 | 1581 | ||
1616 | return 0; | 1582 | return 0; |
1617 | 1583 | ||
@@ -1622,8 +1588,8 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, | |||
1622 | 1588 | ||
1623 | performs display panning - provided hardware permits this | 1589 | performs display panning - provided hardware permits this |
1624 | **************************************************************************/ | 1590 | **************************************************************************/ |
1625 | static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | 1591 | static int cirrusfb_pan_display(struct fb_var_screeninfo *var, |
1626 | struct fb_info *info) | 1592 | struct fb_info *info) |
1627 | { | 1593 | { |
1628 | int xoffset = 0; | 1594 | int xoffset = 0; |
1629 | int yoffset = 0; | 1595 | int yoffset = 0; |
@@ -1631,8 +1597,8 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | |||
1631 | unsigned char tmp = 0, tmp2 = 0, xpix; | 1597 | unsigned char tmp = 0, tmp2 = 0, xpix; |
1632 | struct cirrusfb_info *cinfo = info->par; | 1598 | struct cirrusfb_info *cinfo = info->par; |
1633 | 1599 | ||
1634 | DPRINTK ("ENTER\n"); | 1600 | DPRINTK("ENTER\n"); |
1635 | DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); | 1601 | DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); |
1636 | 1602 | ||
1637 | /* no range checks for xoffset and yoffset, */ | 1603 | /* no range checks for xoffset and yoffset, */ |
1638 | /* as fb_pan_display has already done this */ | 1604 | /* as fb_pan_display has already done this */ |
@@ -1645,7 +1611,7 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | |||
1645 | xoffset = var->xoffset * info->var.bits_per_pixel / 8; | 1611 | xoffset = var->xoffset * info->var.bits_per_pixel / 8; |
1646 | yoffset = var->yoffset; | 1612 | yoffset = var->yoffset; |
1647 | 1613 | ||
1648 | base = yoffset * cinfo->currentmode.line_length + xoffset; | 1614 | base = yoffset * info->fix.line_length + xoffset; |
1649 | 1615 | ||
1650 | if (info->var.bits_per_pixel == 1) { | 1616 | if (info->var.bits_per_pixel == 1) { |
1651 | /* base is already correct */ | 1617 | /* base is already correct */ |
@@ -1655,11 +1621,13 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | |||
1655 | xpix = (unsigned char) ((xoffset % 4) * 2); | 1621 | xpix = (unsigned char) ((xoffset % 4) * 2); |
1656 | } | 1622 | } |
1657 | 1623 | ||
1658 | cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ | 1624 | cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ |
1659 | 1625 | ||
1660 | /* lower 8 + 8 bits of screen start address */ | 1626 | /* lower 8 + 8 bits of screen start address */ |
1661 | vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff)); | 1627 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, |
1662 | vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8)); | 1628 | (unsigned char) (base & 0xff)); |
1629 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, | ||
1630 | (unsigned char) (base >> 8)); | ||
1663 | 1631 | ||
1664 | /* construct bits 16, 17 and 18 of screen start address */ | 1632 | /* construct bits 16, 17 and 18 of screen start address */ |
1665 | if (base & 0x10000) | 1633 | if (base & 0x10000) |
@@ -1669,50 +1637,49 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, | |||
1669 | if (base & 0x40000) | 1637 | if (base & 0x40000) |
1670 | tmp |= 0x08; | 1638 | tmp |= 0x08; |
1671 | 1639 | ||
1672 | tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */ | 1640 | /* 0xf2 is %11110010, exclude tmp bits */ |
1673 | vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2); | 1641 | tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; |
1642 | vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2); | ||
1674 | 1643 | ||
1675 | /* construct bit 19 of screen start address */ | 1644 | /* construct bit 19 of screen start address */ |
1676 | if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) { | 1645 | if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) |
1677 | tmp2 = 0; | 1646 | vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80); |
1678 | if (base & 0x80000) | ||
1679 | tmp2 = 0x80; | ||
1680 | vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2); | ||
1681 | } | ||
1682 | 1647 | ||
1683 | /* write pixel panning value to AR33; this does not quite work in 8bpp */ | 1648 | /* write pixel panning value to AR33; this does not quite work in 8bpp |
1684 | /* ### Piccolo..? Will this work? */ | 1649 | * |
1650 | * ### Piccolo..? Will this work? | ||
1651 | */ | ||
1685 | if (info->var.bits_per_pixel == 1) | 1652 | if (info->var.bits_per_pixel == 1) |
1686 | vga_wattr (cinfo->regbase, CL_AR33, xpix); | 1653 | vga_wattr(cinfo->regbase, CL_AR33, xpix); |
1687 | 1654 | ||
1688 | cirrusfb_WaitBLT (cinfo->regbase); | 1655 | cirrusfb_WaitBLT(cinfo->regbase); |
1689 | 1656 | ||
1690 | DPRINTK ("EXIT\n"); | 1657 | DPRINTK("EXIT\n"); |
1691 | return (0); | 1658 | return 0; |
1692 | } | 1659 | } |
1693 | 1660 | ||
1694 | 1661 | static int cirrusfb_blank(int blank_mode, struct fb_info *info) | |
1695 | static int cirrusfb_blank (int blank_mode, struct fb_info *info) | ||
1696 | { | 1662 | { |
1697 | /* | 1663 | /* |
1698 | * Blank the screen if blank_mode != 0, else unblank. If blank == NULL | 1664 | * Blank the screen if blank_mode != 0, else unblank. If blank == NULL |
1699 | * then the caller blanks by setting the CLUT (Color Look Up Table) to all | 1665 | * then the caller blanks by setting the CLUT (Color Look Up Table) |
1700 | * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due | 1666 | * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking |
1701 | * to e.g. a video mode which doesn't support it. Implements VESA suspend | 1667 | * failed due to e.g. a video mode which doesn't support it. |
1702 | * and powerdown modes on hardware that supports disabling hsync/vsync: | 1668 | * Implements VESA suspend and powerdown modes on hardware that |
1703 | * blank_mode == 2: suspend vsync | 1669 | * supports disabling hsync/vsync: |
1704 | * blank_mode == 3: suspend hsync | 1670 | * blank_mode == 2: suspend vsync |
1705 | * blank_mode == 4: powerdown | 1671 | * blank_mode == 3: suspend hsync |
1672 | * blank_mode == 4: powerdown | ||
1706 | */ | 1673 | */ |
1707 | unsigned char val; | 1674 | unsigned char val; |
1708 | struct cirrusfb_info *cinfo = info->par; | 1675 | struct cirrusfb_info *cinfo = info->par; |
1709 | int current_mode = cinfo->blank_mode; | 1676 | int current_mode = cinfo->blank_mode; |
1710 | 1677 | ||
1711 | DPRINTK ("ENTER, blank mode = %d\n", blank_mode); | 1678 | DPRINTK("ENTER, blank mode = %d\n", blank_mode); |
1712 | 1679 | ||
1713 | if (info->state != FBINFO_STATE_RUNNING || | 1680 | if (info->state != FBINFO_STATE_RUNNING || |
1714 | current_mode == blank_mode) { | 1681 | current_mode == blank_mode) { |
1715 | DPRINTK ("EXIT, returning 0\n"); | 1682 | DPRINTK("EXIT, returning 0\n"); |
1716 | return 0; | 1683 | return 0; |
1717 | } | 1684 | } |
1718 | 1685 | ||
@@ -1720,17 +1687,19 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) | |||
1720 | if (current_mode == FB_BLANK_NORMAL || | 1687 | if (current_mode == FB_BLANK_NORMAL || |
1721 | current_mode == FB_BLANK_UNBLANK) { | 1688 | current_mode == FB_BLANK_UNBLANK) { |
1722 | /* unblank the screen */ | 1689 | /* unblank the screen */ |
1723 | val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); | 1690 | val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); |
1724 | vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */ | 1691 | /* clear "FullBandwidth" bit */ |
1692 | vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); | ||
1725 | /* and undo VESA suspend trickery */ | 1693 | /* and undo VESA suspend trickery */ |
1726 | vga_wgfx (cinfo->regbase, CL_GRE, 0x00); | 1694 | vga_wgfx(cinfo->regbase, CL_GRE, 0x00); |
1727 | } | 1695 | } |
1728 | 1696 | ||
1729 | /* set new */ | 1697 | /* set new */ |
1730 | if(blank_mode > FB_BLANK_NORMAL) { | 1698 | if (blank_mode > FB_BLANK_NORMAL) { |
1731 | /* blank the screen */ | 1699 | /* blank the screen */ |
1732 | val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); | 1700 | val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); |
1733 | vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */ | 1701 | /* set "FullBandwidth" bit */ |
1702 | vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); | ||
1734 | } | 1703 | } |
1735 | 1704 | ||
1736 | switch (blank_mode) { | 1705 | switch (blank_mode) { |
@@ -1738,21 +1707,21 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) | |||
1738 | case FB_BLANK_NORMAL: | 1707 | case FB_BLANK_NORMAL: |
1739 | break; | 1708 | break; |
1740 | case FB_BLANK_VSYNC_SUSPEND: | 1709 | case FB_BLANK_VSYNC_SUSPEND: |
1741 | vga_wgfx (cinfo->regbase, CL_GRE, 0x04); | 1710 | vga_wgfx(cinfo->regbase, CL_GRE, 0x04); |
1742 | break; | 1711 | break; |
1743 | case FB_BLANK_HSYNC_SUSPEND: | 1712 | case FB_BLANK_HSYNC_SUSPEND: |
1744 | vga_wgfx (cinfo->regbase, CL_GRE, 0x02); | 1713 | vga_wgfx(cinfo->regbase, CL_GRE, 0x02); |
1745 | break; | 1714 | break; |
1746 | case FB_BLANK_POWERDOWN: | 1715 | case FB_BLANK_POWERDOWN: |
1747 | vga_wgfx (cinfo->regbase, CL_GRE, 0x06); | 1716 | vga_wgfx(cinfo->regbase, CL_GRE, 0x06); |
1748 | break; | 1717 | break; |
1749 | default: | 1718 | default: |
1750 | DPRINTK ("EXIT, returning 1\n"); | 1719 | DPRINTK("EXIT, returning 1\n"); |
1751 | return 1; | 1720 | return 1; |
1752 | } | 1721 | } |
1753 | 1722 | ||
1754 | cinfo->blank_mode = blank_mode; | 1723 | cinfo->blank_mode = blank_mode; |
1755 | DPRINTK ("EXIT, returning 0\n"); | 1724 | DPRINTK("EXIT, returning 0\n"); |
1756 | 1725 | ||
1757 | /* Let fbcon do a soft blank for us */ | 1726 | /* Let fbcon do a soft blank for us */ |
1758 | return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; | 1727 | return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; |
@@ -1761,45 +1730,51 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) | |||
1761 | /****************************************************************************/ | 1730 | /****************************************************************************/ |
1762 | /**** BEGIN Internal Routines ***********************************************/ | 1731 | /**** BEGIN Internal Routines ***********************************************/ |
1763 | 1732 | ||
1764 | static void init_vgachip (struct cirrusfb_info *cinfo) | 1733 | static void init_vgachip(struct fb_info *info) |
1765 | { | 1734 | { |
1735 | struct cirrusfb_info *cinfo = info->par; | ||
1766 | const struct cirrusfb_board_info_rec *bi; | 1736 | const struct cirrusfb_board_info_rec *bi; |
1767 | 1737 | ||
1768 | DPRINTK ("ENTER\n"); | 1738 | DPRINTK("ENTER\n"); |
1769 | 1739 | ||
1770 | assert (cinfo != NULL); | 1740 | assert(cinfo != NULL); |
1771 | 1741 | ||
1772 | bi = &cirrusfb_board_info[cinfo->btype]; | 1742 | bi = &cirrusfb_board_info[cinfo->btype]; |
1773 | 1743 | ||
1774 | /* reset board globally */ | 1744 | /* reset board globally */ |
1775 | switch (cinfo->btype) { | 1745 | switch (cinfo->btype) { |
1776 | case BT_PICCOLO: | 1746 | case BT_PICCOLO: |
1777 | WSFR (cinfo, 0x01); | 1747 | WSFR(cinfo, 0x01); |
1778 | udelay (500); | 1748 | udelay(500); |
1779 | WSFR (cinfo, 0x51); | 1749 | WSFR(cinfo, 0x51); |
1780 | udelay (500); | 1750 | udelay(500); |
1781 | break; | 1751 | break; |
1782 | case BT_PICASSO: | 1752 | case BT_PICASSO: |
1783 | WSFR2 (cinfo, 0xff); | 1753 | WSFR2(cinfo, 0xff); |
1784 | udelay (500); | 1754 | udelay(500); |
1785 | break; | 1755 | break; |
1786 | case BT_SD64: | 1756 | case BT_SD64: |
1787 | case BT_SPECTRUM: | 1757 | case BT_SPECTRUM: |
1788 | WSFR (cinfo, 0x1f); | 1758 | WSFR(cinfo, 0x1f); |
1789 | udelay (500); | 1759 | udelay(500); |
1790 | WSFR (cinfo, 0x4f); | 1760 | WSFR(cinfo, 0x4f); |
1791 | udelay (500); | 1761 | udelay(500); |
1792 | break; | 1762 | break; |
1793 | case BT_PICASSO4: | 1763 | case BT_PICASSO4: |
1794 | vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */ | 1764 | /* disable flickerfixer */ |
1795 | mdelay (100); | 1765 | vga_wcrt(cinfo->regbase, CL_CRT51, 0x00); |
1796 | vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ | 1766 | mdelay(100); |
1797 | vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */ | 1767 | /* from Klaus' NetBSD driver: */ |
1798 | vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */ | 1768 | vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); |
1769 | /* put blitter into 542x compat */ | ||
1770 | vga_wgfx(cinfo->regbase, CL_GR33, 0x00); | ||
1771 | /* mode */ | ||
1772 | vga_wgfx(cinfo->regbase, CL_GR31, 0x00); | ||
1799 | break; | 1773 | break; |
1800 | 1774 | ||
1801 | case BT_GD5480: | 1775 | case BT_GD5480: |
1802 | vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ | 1776 | /* from Klaus' NetBSD driver: */ |
1777 | vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); | ||
1803 | break; | 1778 | break; |
1804 | 1779 | ||
1805 | case BT_ALPINE: | 1780 | case BT_ALPINE: |
@@ -1807,153 +1782,208 @@ static void init_vgachip (struct cirrusfb_info *cinfo) | |||
1807 | break; | 1782 | break; |
1808 | 1783 | ||
1809 | default: | 1784 | default: |
1810 | printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n"); | 1785 | printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n"); |
1811 | break; | 1786 | break; |
1812 | } | 1787 | } |
1813 | 1788 | ||
1814 | assert (cinfo->size > 0); /* make sure RAM size set by this point */ | 1789 | /* make sure RAM size set by this point */ |
1790 | assert(info->screen_size > 0); | ||
1815 | 1791 | ||
1816 | /* the P4 is not fully initialized here; I rely on it having been */ | 1792 | /* the P4 is not fully initialized here; I rely on it having been */ |
1817 | /* inited under AmigaOS already, which seems to work just fine */ | 1793 | /* inited under AmigaOS already, which seems to work just fine */ |
1818 | /* (Klaus advised to do it this way) */ | 1794 | /* (Klaus advised to do it this way) */ |
1819 | 1795 | ||
1820 | if (cinfo->btype != BT_PICASSO4) { | 1796 | if (cinfo->btype != BT_PICASSO4) { |
1821 | WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */ | 1797 | WGen(cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */ |
1822 | WGen (cinfo, CL_POS102, 0x01); | 1798 | WGen(cinfo, CL_POS102, 0x01); |
1823 | WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */ | 1799 | WGen(cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */ |
1824 | 1800 | ||
1825 | if (cinfo->btype != BT_SD64) | 1801 | if (cinfo->btype != BT_SD64) |
1826 | WGen (cinfo, CL_VSSM2, 0x01); | 1802 | WGen(cinfo, CL_VSSM2, 0x01); |
1827 | 1803 | ||
1828 | vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */ | 1804 | /* reset sequencer logic */ |
1805 | vga_wseq(cinfo->regbase, CL_SEQR0, 0x03); | ||
1829 | 1806 | ||
1830 | vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */ | 1807 | /* FullBandwidth (video off) and 8/9 dot clock */ |
1831 | WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */ | 1808 | vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); |
1809 | /* polarity (-/-), disable access to display memory, | ||
1810 | * VGA_CRTC_START_HI base address: color | ||
1811 | */ | ||
1812 | WGen(cinfo, VGA_MIS_W, 0xc1); | ||
1832 | 1813 | ||
1833 | /* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */ | 1814 | /* "magic cookie" - doesn't make any sense to me.. */ |
1834 | vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */ | 1815 | /* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ |
1816 | /* unlock all extension registers */ | ||
1817 | vga_wseq(cinfo->regbase, CL_SEQR6, 0x12); | ||
1835 | 1818 | ||
1836 | vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */ | 1819 | /* reset blitter */ |
1820 | vga_wgfx(cinfo->regbase, CL_GR31, 0x04); | ||
1837 | 1821 | ||
1838 | switch (cinfo->btype) { | 1822 | switch (cinfo->btype) { |
1839 | case BT_GD5480: | 1823 | case BT_GD5480: |
1840 | vga_wseq (cinfo->regbase, CL_SEQRF, 0x98); | 1824 | vga_wseq(cinfo->regbase, CL_SEQRF, 0x98); |
1841 | break; | 1825 | break; |
1842 | case BT_ALPINE: | 1826 | case BT_ALPINE: |
1843 | break; | 1827 | break; |
1844 | case BT_SD64: | 1828 | case BT_SD64: |
1845 | vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8); | 1829 | vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8); |
1846 | break; | 1830 | break; |
1847 | default: | 1831 | default: |
1848 | vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f); | 1832 | vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f); |
1849 | vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0); | 1833 | vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0); |
1850 | break; | 1834 | break; |
1851 | } | 1835 | } |
1852 | } | 1836 | } |
1853 | vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */ | 1837 | /* plane mask: nothing */ |
1854 | vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */ | 1838 | vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); |
1855 | vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */ | 1839 | /* character map select: doesn't even matter in gx mode */ |
1840 | vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); | ||
1841 | /* memory mode: chain-4, no odd/even, ext. memory */ | ||
1842 | vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); | ||
1856 | 1843 | ||
1857 | /* controller-internal base address of video memory */ | 1844 | /* controller-internal base address of video memory */ |
1858 | if (bi->init_sr07) | 1845 | if (bi->init_sr07) |
1859 | vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07); | 1846 | vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07); |
1860 | 1847 | ||
1861 | /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */ | 1848 | /* vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */ |
1849 | /* EEPROM control: shouldn't be necessary to write to this at all.. */ | ||
1862 | 1850 | ||
1863 | vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */ | 1851 | /* graphics cursor X position (incomplete; position gives rem. 3 bits */ |
1864 | vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */ | 1852 | vga_wseq(cinfo->regbase, CL_SEQR10, 0x00); |
1865 | vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */ | 1853 | /* graphics cursor Y position (..."... ) */ |
1866 | vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */ | 1854 | vga_wseq(cinfo->regbase, CL_SEQR11, 0x00); |
1855 | /* graphics cursor attributes */ | ||
1856 | vga_wseq(cinfo->regbase, CL_SEQR12, 0x00); | ||
1857 | /* graphics cursor pattern address */ | ||
1858 | vga_wseq(cinfo->regbase, CL_SEQR13, 0x00); | ||
1867 | 1859 | ||
1868 | /* writing these on a P4 might give problems.. */ | 1860 | /* writing these on a P4 might give problems.. */ |
1869 | if (cinfo->btype != BT_PICASSO4) { | 1861 | if (cinfo->btype != BT_PICASSO4) { |
1870 | vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */ | 1862 | /* configuration readback and ext. color */ |
1871 | vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */ | 1863 | vga_wseq(cinfo->regbase, CL_SEQR17, 0x00); |
1864 | /* signature generator */ | ||
1865 | vga_wseq(cinfo->regbase, CL_SEQR18, 0x02); | ||
1872 | } | 1866 | } |
1873 | 1867 | ||
1874 | /* MCLK select etc. */ | 1868 | /* MCLK select etc. */ |
1875 | if (bi->init_sr1f) | 1869 | if (bi->init_sr1f) |
1876 | vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f); | 1870 | vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f); |
1877 | 1871 | ||
1878 | vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */ | 1872 | /* Screen A preset row scan: none */ |
1879 | vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */ | 1873 | vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); |
1880 | vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */ | 1874 | /* Text cursor start: disable text cursor */ |
1881 | vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */ | 1875 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); |
1882 | vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */ | 1876 | /* Text cursor end: - */ |
1883 | vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */ | 1877 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); |
1884 | vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */ | 1878 | /* Screen start address high: 0 */ |
1885 | 1879 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00); | |
1886 | vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */ | 1880 | /* Screen start address low: 0 */ |
1887 | vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */ | 1881 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00); |
1888 | vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */ | 1882 | /* text cursor location high: 0 */ |
1883 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); | ||
1884 | /* text cursor location low: 0 */ | ||
1885 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); | ||
1886 | |||
1887 | /* Underline Row scanline: - */ | ||
1888 | vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); | ||
1889 | /* mode control: timing enable, byte mode, no compat modes */ | ||
1890 | vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3); | ||
1891 | /* Line Compare: not needed */ | ||
1892 | vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); | ||
1889 | /* ### add 0x40 for text modes with > 30 MHz pixclock */ | 1893 | /* ### add 0x40 for text modes with > 30 MHz pixclock */ |
1890 | vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */ | 1894 | /* ext. display controls: ext.adr. wrap */ |
1891 | 1895 | vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); | |
1892 | vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */ | 1896 | |
1893 | vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */ | 1897 | /* Set/Reset registes: - */ |
1894 | vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */ | 1898 | vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); |
1895 | vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */ | 1899 | /* Set/Reset enable: - */ |
1896 | vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */ | 1900 | vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); |
1897 | vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ | 1901 | /* Color Compare: - */ |
1898 | vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */ | 1902 | vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); |
1899 | vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */ | 1903 | /* Data Rotate: - */ |
1900 | vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */ | 1904 | vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); |
1905 | /* Read Map Select: - */ | ||
1906 | vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); | ||
1907 | /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ | ||
1908 | vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00); | ||
1909 | /* Miscellaneous: memory map base address, graphics mode */ | ||
1910 | vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01); | ||
1911 | /* Color Don't care: involve all planes */ | ||
1912 | vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); | ||
1913 | /* Bit Mask: no mask at all */ | ||
1914 | vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); | ||
1901 | if (cinfo->btype == BT_ALPINE) | 1915 | if (cinfo->btype == BT_ALPINE) |
1902 | vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */ | 1916 | /* (5434 can't have bit 3 set for bitblt) */ |
1917 | vga_wgfx(cinfo->regbase, CL_GRB, 0x20); | ||
1903 | else | 1918 | else |
1904 | vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */ | 1919 | /* Graphics controller mode extensions: finer granularity, |
1905 | 1920 | * 8byte data latches | |
1906 | vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */ | 1921 | */ |
1907 | vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */ | 1922 | vga_wgfx(cinfo->regbase, CL_GRB, 0x28); |
1908 | vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */ | 1923 | |
1909 | /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */ | 1924 | vga_wgfx(cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */ |
1910 | /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */ | 1925 | vga_wgfx(cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */ |
1911 | 1926 | vga_wgfx(cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */ | |
1912 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */ | 1927 | /* Background color byte 1: - */ |
1913 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01); | 1928 | /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */ |
1914 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02); | 1929 | /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */ |
1915 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03); | 1930 | |
1916 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04); | 1931 | /* Attribute Controller palette registers: "identity mapping" */ |
1917 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05); | 1932 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00); |
1918 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06); | 1933 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01); |
1919 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07); | 1934 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02); |
1920 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08); | 1935 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03); |
1921 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09); | 1936 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04); |
1922 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a); | 1937 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05); |
1923 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b); | 1938 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06); |
1924 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c); | 1939 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07); |
1925 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d); | 1940 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08); |
1926 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e); | 1941 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09); |
1927 | vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f); | 1942 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a); |
1928 | 1943 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b); | |
1929 | vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */ | 1944 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c); |
1930 | vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */ | 1945 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d); |
1931 | vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */ | 1946 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e); |
1932 | /* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ | 1947 | vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f); |
1933 | vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */ | 1948 | |
1934 | 1949 | /* Attribute Controller mode: graphics mode */ | |
1935 | WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ | 1950 | vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01); |
1951 | /* Overscan color reg.: reg. 0 */ | ||
1952 | vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); | ||
1953 | /* Color Plane enable: Enable all 4 planes */ | ||
1954 | vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); | ||
1955 | /* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ | ||
1956 | /* Color Select: - */ | ||
1957 | vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); | ||
1958 | |||
1959 | WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ | ||
1936 | 1960 | ||
1937 | if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) | 1961 | if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) |
1938 | WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */ | 1962 | /* polarity (-/-), enable display mem, |
1963 | * VGA_CRTC_START_HI i/o base = color | ||
1964 | */ | ||
1965 | WGen(cinfo, VGA_MIS_W, 0xc3); | ||
1939 | 1966 | ||
1940 | vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */ | 1967 | /* BLT Start/status: Blitter reset */ |
1941 | vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */ | 1968 | vga_wgfx(cinfo->regbase, CL_GR31, 0x04); |
1969 | /* - " - : "end-of-reset" */ | ||
1970 | vga_wgfx(cinfo->regbase, CL_GR31, 0x00); | ||
1942 | 1971 | ||
1943 | /* misc... */ | 1972 | /* misc... */ |
1944 | WHDR (cinfo, 0); /* Hidden DAC register: - */ | 1973 | WHDR(cinfo, 0); /* Hidden DAC register: - */ |
1945 | 1974 | ||
1946 | printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size); | 1975 | printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", |
1947 | DPRINTK ("EXIT\n"); | 1976 | info->screen_size); |
1977 | DPRINTK("EXIT\n"); | ||
1948 | return; | 1978 | return; |
1949 | } | 1979 | } |
1950 | 1980 | ||
1951 | static void switch_monitor (struct cirrusfb_info *cinfo, int on) | 1981 | static void switch_monitor(struct cirrusfb_info *cinfo, int on) |
1952 | { | 1982 | { |
1953 | #ifdef CONFIG_ZORRO /* only works on Zorro boards */ | 1983 | #ifdef CONFIG_ZORRO /* only works on Zorro boards */ |
1954 | static int IsOn = 0; /* XXX not ok for multiple boards */ | 1984 | static int IsOn = 0; /* XXX not ok for multiple boards */ |
1955 | 1985 | ||
1956 | DPRINTK ("ENTER\n"); | 1986 | DPRINTK("ENTER\n"); |
1957 | 1987 | ||
1958 | if (cinfo->btype == BT_PICASSO4) | 1988 | if (cinfo->btype == BT_PICASSO4) |
1959 | return; /* nothing to switch */ | 1989 | return; /* nothing to switch */ |
@@ -1963,77 +1993,56 @@ static void switch_monitor (struct cirrusfb_info *cinfo, int on) | |||
1963 | return; /* nothing to switch */ | 1993 | return; /* nothing to switch */ |
1964 | if (cinfo->btype == BT_PICASSO) { | 1994 | if (cinfo->btype == BT_PICASSO) { |
1965 | if ((on && !IsOn) || (!on && IsOn)) | 1995 | if ((on && !IsOn) || (!on && IsOn)) |
1966 | WSFR (cinfo, 0xff); | 1996 | WSFR(cinfo, 0xff); |
1967 | 1997 | ||
1968 | DPRINTK ("EXIT\n"); | 1998 | DPRINTK("EXIT\n"); |
1969 | return; | 1999 | return; |
1970 | } | 2000 | } |
1971 | if (on) { | 2001 | if (on) { |
1972 | switch (cinfo->btype) { | 2002 | switch (cinfo->btype) { |
1973 | case BT_SD64: | 2003 | case BT_SD64: |
1974 | WSFR (cinfo, cinfo->SFR | 0x21); | 2004 | WSFR(cinfo, cinfo->SFR | 0x21); |
1975 | break; | 2005 | break; |
1976 | case BT_PICCOLO: | 2006 | case BT_PICCOLO: |
1977 | WSFR (cinfo, cinfo->SFR | 0x28); | 2007 | WSFR(cinfo, cinfo->SFR | 0x28); |
1978 | break; | 2008 | break; |
1979 | case BT_SPECTRUM: | 2009 | case BT_SPECTRUM: |
1980 | WSFR (cinfo, 0x6f); | 2010 | WSFR(cinfo, 0x6f); |
1981 | break; | 2011 | break; |
1982 | default: /* do nothing */ break; | 2012 | default: /* do nothing */ break; |
1983 | } | 2013 | } |
1984 | } else { | 2014 | } else { |
1985 | switch (cinfo->btype) { | 2015 | switch (cinfo->btype) { |
1986 | case BT_SD64: | 2016 | case BT_SD64: |
1987 | WSFR (cinfo, cinfo->SFR & 0xde); | 2017 | WSFR(cinfo, cinfo->SFR & 0xde); |
1988 | break; | 2018 | break; |
1989 | case BT_PICCOLO: | 2019 | case BT_PICCOLO: |
1990 | WSFR (cinfo, cinfo->SFR & 0xd7); | 2020 | WSFR(cinfo, cinfo->SFR & 0xd7); |
1991 | break; | 2021 | break; |
1992 | case BT_SPECTRUM: | 2022 | case BT_SPECTRUM: |
1993 | WSFR (cinfo, 0x4f); | 2023 | WSFR(cinfo, 0x4f); |
1994 | break; | 2024 | break; |
1995 | default: /* do nothing */ break; | 2025 | default: /* do nothing */ break; |
1996 | } | 2026 | } |
1997 | } | 2027 | } |
1998 | 2028 | ||
1999 | DPRINTK ("EXIT\n"); | 2029 | DPRINTK("EXIT\n"); |
2000 | #endif /* CONFIG_ZORRO */ | 2030 | #endif /* CONFIG_ZORRO */ |
2001 | } | 2031 | } |
2002 | 2032 | ||
2003 | |||
2004 | /******************************************/ | 2033 | /******************************************/ |
2005 | /* Linux 2.6-style accelerated functions */ | 2034 | /* Linux 2.6-style accelerated functions */ |
2006 | /******************************************/ | 2035 | /******************************************/ |
2007 | 2036 | ||
2008 | static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo, | 2037 | static void cirrusfb_fillrect(struct fb_info *info, |
2009 | const struct fb_fillrect *region) | 2038 | const struct fb_fillrect *region) |
2010 | { | ||
2011 | int m; /* bytes per pixel */ | ||
2012 | u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ? | ||
2013 | cinfo->pseudo_palette[region->color] : region->color; | ||
2014 | |||
2015 | if(cinfo->info->var.bits_per_pixel == 1) { | ||
2016 | cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, | ||
2017 | region->dx / 8, region->dy, | ||
2018 | region->width / 8, region->height, | ||
2019 | color, | ||
2020 | cinfo->currentmode.line_length); | ||
2021 | } else { | ||
2022 | m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; | ||
2023 | cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, | ||
2024 | region->dx * m, region->dy, | ||
2025 | region->width * m, region->height, | ||
2026 | color, | ||
2027 | cinfo->currentmode.line_length); | ||
2028 | } | ||
2029 | return; | ||
2030 | } | ||
2031 | |||
2032 | static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region) | ||
2033 | { | 2039 | { |
2034 | struct cirrusfb_info *cinfo = info->par; | ||
2035 | struct fb_fillrect modded; | 2040 | struct fb_fillrect modded; |
2036 | int vxres, vyres; | 2041 | int vxres, vyres; |
2042 | struct cirrusfb_info *cinfo = info->par; | ||
2043 | int m = info->var.bits_per_pixel; | ||
2044 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | ||
2045 | cinfo->pseudo_palette[region->color] : region->color; | ||
2037 | 2046 | ||
2038 | if (info->state != FBINFO_STATE_RUNNING) | 2047 | if (info->state != FBINFO_STATE_RUNNING) |
2039 | return; | 2048 | return; |
@@ -2047,49 +2056,30 @@ static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *r | |||
2047 | 2056 | ||
2048 | memcpy(&modded, region, sizeof(struct fb_fillrect)); | 2057 | memcpy(&modded, region, sizeof(struct fb_fillrect)); |
2049 | 2058 | ||
2050 | if(!modded.width || !modded.height || | 2059 | if (!modded.width || !modded.height || |
2051 | modded.dx >= vxres || modded.dy >= vyres) | 2060 | modded.dx >= vxres || modded.dy >= vyres) |
2052 | return; | 2061 | return; |
2053 | 2062 | ||
2054 | if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; | 2063 | if (modded.dx + modded.width > vxres) |
2055 | if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; | 2064 | modded.width = vxres - modded.dx; |
2056 | 2065 | if (modded.dy + modded.height > vyres) | |
2057 | cirrusfb_prim_fillrect(cinfo, &modded); | 2066 | modded.height = vyres - modded.dy; |
2058 | } | 2067 | |
2059 | 2068 | cirrusfb_RectFill(cinfo->regbase, | |
2060 | static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo, | 2069 | info->var.bits_per_pixel, |
2061 | const struct fb_copyarea *area) | 2070 | (region->dx * m) / 8, region->dy, |
2062 | { | 2071 | (region->width * m) / 8, region->height, |
2063 | int m; /* bytes per pixel */ | 2072 | color, |
2064 | if(cinfo->info->var.bits_per_pixel == 1) { | 2073 | info->fix.line_length); |
2065 | cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, | ||
2066 | area->sx / 8, area->sy, | ||
2067 | area->dx / 8, area->dy, | ||
2068 | area->width / 8, area->height, | ||
2069 | cinfo->currentmode.line_length); | ||
2070 | } else { | ||
2071 | m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; | ||
2072 | cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, | ||
2073 | area->sx * m, area->sy, | ||
2074 | area->dx * m, area->dy, | ||
2075 | area->width * m, area->height, | ||
2076 | cinfo->currentmode.line_length); | ||
2077 | } | ||
2078 | return; | ||
2079 | } | 2074 | } |
2080 | 2075 | ||
2081 | 2076 | static void cirrusfb_copyarea(struct fb_info *info, | |
2082 | static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | 2077 | const struct fb_copyarea *area) |
2083 | { | 2078 | { |
2084 | struct cirrusfb_info *cinfo = info->par; | ||
2085 | struct fb_copyarea modded; | 2079 | struct fb_copyarea modded; |
2086 | u32 vxres, vyres; | 2080 | u32 vxres, vyres; |
2087 | modded.sx = area->sx; | 2081 | struct cirrusfb_info *cinfo = info->par; |
2088 | modded.sy = area->sy; | 2082 | int m = info->var.bits_per_pixel; |
2089 | modded.dx = area->dx; | ||
2090 | modded.dy = area->dy; | ||
2091 | modded.width = area->width; | ||
2092 | modded.height = area->height; | ||
2093 | 2083 | ||
2094 | if (info->state != FBINFO_STATE_RUNNING) | 2084 | if (info->state != FBINFO_STATE_RUNNING) |
2095 | return; | 2085 | return; |
@@ -2100,90 +2090,106 @@ static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *ar | |||
2100 | 2090 | ||
2101 | vxres = info->var.xres_virtual; | 2091 | vxres = info->var.xres_virtual; |
2102 | vyres = info->var.yres_virtual; | 2092 | vyres = info->var.yres_virtual; |
2093 | memcpy(&modded, area, sizeof(struct fb_copyarea)); | ||
2103 | 2094 | ||
2104 | if(!modded.width || !modded.height || | 2095 | if (!modded.width || !modded.height || |
2105 | modded.sx >= vxres || modded.sy >= vyres || | 2096 | modded.sx >= vxres || modded.sy >= vyres || |
2106 | modded.dx >= vxres || modded.dy >= vyres) | 2097 | modded.dx >= vxres || modded.dy >= vyres) |
2107 | return; | 2098 | return; |
2108 | 2099 | ||
2109 | if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx; | 2100 | if (modded.sx + modded.width > vxres) |
2110 | if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; | 2101 | modded.width = vxres - modded.sx; |
2111 | if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy; | 2102 | if (modded.dx + modded.width > vxres) |
2112 | if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; | 2103 | modded.width = vxres - modded.dx; |
2104 | if (modded.sy + modded.height > vyres) | ||
2105 | modded.height = vyres - modded.sy; | ||
2106 | if (modded.dy + modded.height > vyres) | ||
2107 | modded.height = vyres - modded.dy; | ||
2108 | |||
2109 | cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel, | ||
2110 | (area->sx * m) / 8, area->sy, | ||
2111 | (area->dx * m) / 8, area->dy, | ||
2112 | (area->width * m) / 8, area->height, | ||
2113 | info->fix.line_length); | ||
2113 | 2114 | ||
2114 | cirrusfb_prim_copyarea(cinfo, &modded); | ||
2115 | } | 2115 | } |
2116 | 2116 | ||
2117 | static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image) | 2117 | static void cirrusfb_imageblit(struct fb_info *info, |
2118 | const struct fb_image *image) | ||
2118 | { | 2119 | { |
2119 | struct cirrusfb_info *cinfo = info->par; | 2120 | struct cirrusfb_info *cinfo = info->par; |
2120 | 2121 | ||
2121 | cirrusfb_WaitBLT(cinfo->regbase); | 2122 | cirrusfb_WaitBLT(cinfo->regbase); |
2122 | cfb_imageblit(info, image); | 2123 | cfb_imageblit(info, image); |
2123 | } | 2124 | } |
2124 | 2125 | ||
2125 | |||
2126 | #ifdef CONFIG_PPC_PREP | 2126 | #ifdef CONFIG_PPC_PREP |
2127 | #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) | 2127 | #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) |
2128 | #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) | 2128 | #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) |
2129 | static void get_prep_addrs (unsigned long *display, unsigned long *registers) | 2129 | static void get_prep_addrs(unsigned long *display, unsigned long *registers) |
2130 | { | 2130 | { |
2131 | DPRINTK ("ENTER\n"); | 2131 | DPRINTK("ENTER\n"); |
2132 | 2132 | ||
2133 | *display = PREP_VIDEO_BASE; | 2133 | *display = PREP_VIDEO_BASE; |
2134 | *registers = (unsigned long) PREP_IO_BASE; | 2134 | *registers = (unsigned long) PREP_IO_BASE; |
2135 | 2135 | ||
2136 | DPRINTK ("EXIT\n"); | 2136 | DPRINTK("EXIT\n"); |
2137 | } | 2137 | } |
2138 | 2138 | ||
2139 | #endif /* CONFIG_PPC_PREP */ | 2139 | #endif /* CONFIG_PPC_PREP */ |
2140 | 2140 | ||
2141 | |||
2142 | #ifdef CONFIG_PCI | 2141 | #ifdef CONFIG_PCI |
2143 | static int release_io_ports = 0; | 2142 | static int release_io_ports; |
2144 | 2143 | ||
2145 | /* Pulled the logic from XFree86 Cirrus driver to get the memory size, | 2144 | /* Pulled the logic from XFree86 Cirrus driver to get the memory size, |
2146 | * based on the DRAM bandwidth bit and DRAM bank switching bit. This | 2145 | * based on the DRAM bandwidth bit and DRAM bank switching bit. This |
2147 | * works with 1MB, 2MB and 4MB configurations (which the Motorola boards | 2146 | * works with 1MB, 2MB and 4MB configurations (which the Motorola boards |
2148 | * seem to have. */ | 2147 | * seem to have. */ |
2149 | static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase) | 2148 | static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase) |
2150 | { | 2149 | { |
2151 | unsigned long mem; | 2150 | unsigned long mem; |
2152 | unsigned char SRF; | 2151 | unsigned char SRF; |
2153 | 2152 | ||
2154 | DPRINTK ("ENTER\n"); | 2153 | DPRINTK("ENTER\n"); |
2155 | 2154 | ||
2156 | SRF = vga_rseq (regbase, CL_SEQRF); | 2155 | SRF = vga_rseq(regbase, CL_SEQRF); |
2157 | switch ((SRF & 0x18)) { | 2156 | switch ((SRF & 0x18)) { |
2158 | case 0x08: mem = 512 * 1024; break; | 2157 | case 0x08: |
2159 | case 0x10: mem = 1024 * 1024; break; | 2158 | mem = 512 * 1024; |
2160 | /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory | 2159 | break; |
2161 | * on the 5430. */ | 2160 | case 0x10: |
2162 | case 0x18: mem = 2048 * 1024; break; | 2161 | mem = 1024 * 1024; |
2163 | default: printk ("CLgenfb: Unknown memory size!\n"); | 2162 | break; |
2163 | /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory | ||
2164 | * on the 5430. | ||
2165 | */ | ||
2166 | case 0x18: | ||
2167 | mem = 2048 * 1024; | ||
2168 | break; | ||
2169 | default: | ||
2170 | printk(KERN_WARNING "CLgenfb: Unknown memory size!\n"); | ||
2164 | mem = 1024 * 1024; | 2171 | mem = 1024 * 1024; |
2165 | } | 2172 | } |
2166 | if (SRF & 0x80) { | 2173 | if (SRF & 0x80) |
2167 | /* If DRAM bank switching is enabled, there must be twice as much | 2174 | /* If DRAM bank switching is enabled, there must be twice as much |
2168 | * memory installed. (4MB on the 5434) */ | 2175 | * memory installed. (4MB on the 5434) |
2176 | */ | ||
2169 | mem *= 2; | 2177 | mem *= 2; |
2170 | } | 2178 | |
2171 | /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ | 2179 | /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ |
2172 | 2180 | ||
2173 | DPRINTK ("EXIT\n"); | 2181 | DPRINTK("EXIT\n"); |
2174 | return mem; | 2182 | return mem; |
2175 | } | 2183 | } |
2176 | 2184 | ||
2177 | 2185 | static void get_pci_addrs(const struct pci_dev *pdev, | |
2178 | 2186 | unsigned long *display, unsigned long *registers) | |
2179 | static void get_pci_addrs (const struct pci_dev *pdev, | ||
2180 | unsigned long *display, unsigned long *registers) | ||
2181 | { | 2187 | { |
2182 | assert (pdev != NULL); | 2188 | assert(pdev != NULL); |
2183 | assert (display != NULL); | 2189 | assert(display != NULL); |
2184 | assert (registers != NULL); | 2190 | assert(registers != NULL); |
2185 | 2191 | ||
2186 | DPRINTK ("ENTER\n"); | 2192 | DPRINTK("ENTER\n"); |
2187 | 2193 | ||
2188 | *display = 0; | 2194 | *display = 0; |
2189 | *registers = 0; | 2195 | *registers = 0; |
@@ -2198,51 +2204,47 @@ static void get_pci_addrs (const struct pci_dev *pdev, | |||
2198 | *registers = pci_resource_start(pdev, 1); | 2204 | *registers = pci_resource_start(pdev, 1); |
2199 | } | 2205 | } |
2200 | 2206 | ||
2201 | assert (*display != 0); | 2207 | assert(*display != 0); |
2202 | 2208 | ||
2203 | DPRINTK ("EXIT\n"); | 2209 | DPRINTK("EXIT\n"); |
2204 | } | 2210 | } |
2205 | 2211 | ||
2206 | 2212 | static void cirrusfb_pci_unmap(struct fb_info *info) | |
2207 | static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo) | ||
2208 | { | 2213 | { |
2214 | struct cirrusfb_info *cinfo = info->par; | ||
2209 | struct pci_dev *pdev = cinfo->pdev; | 2215 | struct pci_dev *pdev = cinfo->pdev; |
2210 | 2216 | ||
2211 | iounmap(cinfo->fbmem); | 2217 | iounmap(info->screen_base); |
2212 | #if 0 /* if system didn't claim this region, we would... */ | 2218 | #if 0 /* if system didn't claim this region, we would... */ |
2213 | release_mem_region(0xA0000, 65535); | 2219 | release_mem_region(0xA0000, 65535); |
2214 | #endif | 2220 | #endif |
2215 | if (release_io_ports) | 2221 | if (release_io_ports) |
2216 | release_region(0x3C0, 32); | 2222 | release_region(0x3C0, 32); |
2217 | pci_release_regions(pdev); | 2223 | pci_release_regions(pdev); |
2218 | framebuffer_release(cinfo->info); | ||
2219 | } | 2224 | } |
2220 | #endif /* CONFIG_PCI */ | 2225 | #endif /* CONFIG_PCI */ |
2221 | 2226 | ||
2222 | |||
2223 | #ifdef CONFIG_ZORRO | 2227 | #ifdef CONFIG_ZORRO |
2224 | static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo) | 2228 | static void __devexit cirrusfb_zorro_unmap(struct cirrusfb_info *cinfo) |
2225 | { | 2229 | { |
2226 | zorro_release_device(cinfo->zdev); | 2230 | zorro_release_device(cinfo->zdev); |
2227 | 2231 | ||
2228 | if (cinfo->btype == BT_PICASSO4) { | 2232 | if (cinfo->btype == BT_PICASSO4) { |
2229 | cinfo->regbase -= 0x600000; | 2233 | cinfo->regbase -= 0x600000; |
2230 | iounmap ((void *)cinfo->regbase); | 2234 | iounmap((void *)cinfo->regbase); |
2231 | iounmap ((void *)cinfo->fbmem); | 2235 | iounmap(info->screen_base); |
2232 | } else { | 2236 | } else { |
2233 | if (zorro_resource_start(cinfo->zdev) > 0x01000000) | 2237 | if (zorro_resource_start(cinfo->zdev) > 0x01000000) |
2234 | iounmap ((void *)cinfo->fbmem); | 2238 | iounmap(info->screen_base); |
2235 | } | 2239 | } |
2236 | framebuffer_release(cinfo->info); | ||
2237 | } | 2240 | } |
2238 | #endif /* CONFIG_ZORRO */ | 2241 | #endif /* CONFIG_ZORRO */ |
2239 | 2242 | ||
2240 | static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) | 2243 | static int cirrusfb_set_fbinfo(struct fb_info *info) |
2241 | { | 2244 | { |
2242 | struct fb_info *info = cinfo->info; | 2245 | struct cirrusfb_info *cinfo = info->par; |
2243 | struct fb_var_screeninfo *var = &info->var; | 2246 | struct fb_var_screeninfo *var = &info->var; |
2244 | 2247 | ||
2245 | info->par = cinfo; | ||
2246 | info->pseudo_palette = cinfo->pseudo_palette; | 2248 | info->pseudo_palette = cinfo->pseudo_palette; |
2247 | info->flags = FBINFO_DEFAULT | 2249 | info->flags = FBINFO_DEFAULT |
2248 | | FBINFO_HWACCEL_XPAN | 2250 | | FBINFO_HWACCEL_XPAN |
@@ -2252,7 +2254,6 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) | |||
2252 | if (noaccel) | 2254 | if (noaccel) |
2253 | info->flags |= FBINFO_HWACCEL_DISABLED; | 2255 | info->flags |= FBINFO_HWACCEL_DISABLED; |
2254 | info->fbops = &cirrusfb_ops; | 2256 | info->fbops = &cirrusfb_ops; |
2255 | info->screen_base = cinfo->fbmem; | ||
2256 | if (cinfo->btype == BT_GD5480) { | 2257 | if (cinfo->btype == BT_GD5480) { |
2257 | if (var->bits_per_pixel == 16) | 2258 | if (var->bits_per_pixel == 16) |
2258 | info->screen_base += 1 * MB_; | 2259 | info->screen_base += 1 * MB_; |
@@ -2266,18 +2267,15 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) | |||
2266 | 2267 | ||
2267 | /* monochrome: only 1 memory plane */ | 2268 | /* monochrome: only 1 memory plane */ |
2268 | /* 8 bit and above: Use whole memory area */ | 2269 | /* 8 bit and above: Use whole memory area */ |
2269 | info->fix.smem_start = cinfo->fbmem_phys; | 2270 | info->fix.smem_len = info->screen_size; |
2270 | info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size; | 2271 | if (var->bits_per_pixel == 1) |
2271 | info->fix.type = cinfo->currentmode.type; | 2272 | info->fix.smem_len /= 4; |
2272 | info->fix.type_aux = 0; | 2273 | info->fix.type_aux = 0; |
2273 | info->fix.visual = cinfo->currentmode.visual; | ||
2274 | info->fix.xpanstep = 1; | 2274 | info->fix.xpanstep = 1; |
2275 | info->fix.ypanstep = 1; | 2275 | info->fix.ypanstep = 1; |
2276 | info->fix.ywrapstep = 0; | 2276 | info->fix.ywrapstep = 0; |
2277 | info->fix.line_length = cinfo->currentmode.line_length; | ||
2278 | 2277 | ||
2279 | /* FIXME: map region at 0xB8000 if available, fill in here */ | 2278 | /* FIXME: map region at 0xB8000 if available, fill in here */ |
2280 | info->fix.mmio_start = cinfo->fbregs_phys; | ||
2281 | info->fix.mmio_len = 0; | 2279 | info->fix.mmio_len = 0; |
2282 | info->fix.accel = FB_ACCEL_NONE; | 2280 | info->fix.accel = FB_ACCEL_NONE; |
2283 | 2281 | ||
@@ -2286,23 +2284,23 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) | |||
2286 | return 0; | 2284 | return 0; |
2287 | } | 2285 | } |
2288 | 2286 | ||
2289 | static int cirrusfb_register(struct cirrusfb_info *cinfo) | 2287 | static int cirrusfb_register(struct fb_info *info) |
2290 | { | 2288 | { |
2291 | struct fb_info *info; | 2289 | struct cirrusfb_info *cinfo = info->par; |
2292 | int err; | 2290 | int err; |
2293 | cirrusfb_board_t btype; | 2291 | enum cirrus_board btype; |
2294 | 2292 | ||
2295 | DPRINTK ("ENTER\n"); | 2293 | DPRINTK("ENTER\n"); |
2296 | 2294 | ||
2297 | printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n"); | 2295 | printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based " |
2296 | "graphic boards, v" CIRRUSFB_VERSION "\n"); | ||
2298 | 2297 | ||
2299 | info = cinfo->info; | ||
2300 | btype = cinfo->btype; | 2298 | btype = cinfo->btype; |
2301 | 2299 | ||
2302 | /* sanity checks */ | 2300 | /* sanity checks */ |
2303 | assert (btype != BT_NONE); | 2301 | assert(btype != BT_NONE); |
2304 | 2302 | ||
2305 | DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem); | 2303 | DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base); |
2306 | 2304 | ||
2307 | /* Make pretend we've set the var so our structures are in a "good" */ | 2305 | /* Make pretend we've set the var so our structures are in a "good" */ |
2308 | /* state, even though we haven't written the mode to the hw yet... */ | 2306 | /* state, even though we haven't written the mode to the hw yet... */ |
@@ -2317,47 +2315,49 @@ static int cirrusfb_register(struct cirrusfb_info *cinfo) | |||
2317 | } | 2315 | } |
2318 | 2316 | ||
2319 | /* set all the vital stuff */ | 2317 | /* set all the vital stuff */ |
2320 | cirrusfb_set_fbinfo(cinfo); | 2318 | cirrusfb_set_fbinfo(info); |
2321 | 2319 | ||
2322 | err = register_framebuffer(info); | 2320 | err = register_framebuffer(info); |
2323 | if (err < 0) { | 2321 | if (err < 0) { |
2324 | printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err); | 2322 | printk(KERN_ERR "cirrusfb: could not register " |
2323 | "fb device; err = %d!\n", err); | ||
2325 | goto err_dealloc_cmap; | 2324 | goto err_dealloc_cmap; |
2326 | } | 2325 | } |
2327 | 2326 | ||
2328 | DPRINTK ("EXIT, returning 0\n"); | 2327 | DPRINTK("EXIT, returning 0\n"); |
2329 | return 0; | 2328 | return 0; |
2330 | 2329 | ||
2331 | err_dealloc_cmap: | 2330 | err_dealloc_cmap: |
2332 | fb_dealloc_cmap(&info->cmap); | 2331 | fb_dealloc_cmap(&info->cmap); |
2333 | err_unmap_cirrusfb: | 2332 | err_unmap_cirrusfb: |
2334 | cinfo->unmap(cinfo); | 2333 | cinfo->unmap(info); |
2334 | framebuffer_release(info); | ||
2335 | return err; | 2335 | return err; |
2336 | } | 2336 | } |
2337 | 2337 | ||
2338 | static void __devexit cirrusfb_cleanup (struct fb_info *info) | 2338 | static void __devexit cirrusfb_cleanup(struct fb_info *info) |
2339 | { | 2339 | { |
2340 | struct cirrusfb_info *cinfo = info->par; | 2340 | struct cirrusfb_info *cinfo = info->par; |
2341 | DPRINTK ("ENTER\n"); | 2341 | DPRINTK("ENTER\n"); |
2342 | 2342 | ||
2343 | switch_monitor (cinfo, 0); | 2343 | switch_monitor(cinfo, 0); |
2344 | 2344 | ||
2345 | unregister_framebuffer (info); | 2345 | unregister_framebuffer(info); |
2346 | fb_dealloc_cmap (&info->cmap); | 2346 | fb_dealloc_cmap(&info->cmap); |
2347 | printk ("Framebuffer unregistered\n"); | 2347 | printk("Framebuffer unregistered\n"); |
2348 | cinfo->unmap(cinfo); | 2348 | cinfo->unmap(info); |
2349 | framebuffer_release(info); | ||
2349 | 2350 | ||
2350 | DPRINTK ("EXIT\n"); | 2351 | DPRINTK("EXIT\n"); |
2351 | } | 2352 | } |
2352 | 2353 | ||
2353 | |||
2354 | #ifdef CONFIG_PCI | 2354 | #ifdef CONFIG_PCI |
2355 | static int cirrusfb_pci_register (struct pci_dev *pdev, | 2355 | static int cirrusfb_pci_register(struct pci_dev *pdev, |
2356 | const struct pci_device_id *ent) | 2356 | const struct pci_device_id *ent) |
2357 | { | 2357 | { |
2358 | struct cirrusfb_info *cinfo; | 2358 | struct cirrusfb_info *cinfo; |
2359 | struct fb_info *info; | 2359 | struct fb_info *info; |
2360 | cirrusfb_board_t btype; | 2360 | enum cirrus_board btype; |
2361 | unsigned long board_addr, board_size; | 2361 | unsigned long board_addr, board_size; |
2362 | int ret; | 2362 | int ret; |
2363 | 2363 | ||
@@ -2375,35 +2375,37 @@ static int cirrusfb_pci_register (struct pci_dev *pdev, | |||
2375 | } | 2375 | } |
2376 | 2376 | ||
2377 | cinfo = info->par; | 2377 | cinfo = info->par; |
2378 | cinfo->info = info; | ||
2379 | cinfo->pdev = pdev; | 2378 | cinfo->pdev = pdev; |
2380 | cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data; | 2379 | cinfo->btype = btype = (enum cirrus_board) ent->driver_data; |
2381 | 2380 | ||
2382 | DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n", | 2381 | DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n", |
2383 | pdev->resource[0].start, btype); | 2382 | pdev->resource[0].start, btype); |
2384 | DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start); | 2383 | DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start); |
2385 | 2384 | ||
2386 | if(isPReP) { | 2385 | if (isPReP) { |
2387 | pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000); | 2386 | pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000); |
2388 | #ifdef CONFIG_PPC_PREP | 2387 | #ifdef CONFIG_PPC_PREP |
2389 | get_prep_addrs (&board_addr, &cinfo->fbregs_phys); | 2388 | get_prep_addrs(&board_addr, &info->fix.mmio_start); |
2390 | #endif | 2389 | #endif |
2391 | /* PReP dies if we ioremap the IO registers, but it works w/out... */ | 2390 | /* PReP dies if we ioremap the IO registers, but it works w/out... */ |
2392 | cinfo->regbase = (char __iomem *) cinfo->fbregs_phys; | 2391 | cinfo->regbase = (char __iomem *) info->fix.mmio_start; |
2393 | } else { | 2392 | } else { |
2394 | DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); | 2393 | DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n"); |
2395 | get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys); | 2394 | get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start); |
2396 | cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */ | 2395 | /* FIXME: this forces VGA. alternatives? */ |
2396 | cinfo->regbase = NULL; | ||
2397 | } | 2397 | } |
2398 | 2398 | ||
2399 | DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys); | 2399 | DPRINTK("Board address: 0x%lx, register address: 0x%lx\n", |
2400 | board_addr, info->fix.mmio_start); | ||
2400 | 2401 | ||
2401 | board_size = (btype == BT_GD5480) ? | 2402 | board_size = (btype == BT_GD5480) ? |
2402 | 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase); | 2403 | 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase); |
2403 | 2404 | ||
2404 | ret = pci_request_regions(pdev, "cirrusfb"); | 2405 | ret = pci_request_regions(pdev, "cirrusfb"); |
2405 | if (ret <0) { | 2406 | if (ret < 0) { |
2406 | printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", | 2407 | printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " |
2408 | "abort\n", | ||
2407 | board_addr); | 2409 | board_addr); |
2408 | goto err_release_fb; | 2410 | goto err_release_fb; |
2409 | } | 2411 | } |
@@ -2419,23 +2421,24 @@ static int cirrusfb_pci_register (struct pci_dev *pdev, | |||
2419 | if (request_region(0x3C0, 32, "cirrusfb")) | 2421 | if (request_region(0x3C0, 32, "cirrusfb")) |
2420 | release_io_ports = 1; | 2422 | release_io_ports = 1; |
2421 | 2423 | ||
2422 | cinfo->fbmem = ioremap(board_addr, board_size); | 2424 | info->screen_base = ioremap(board_addr, board_size); |
2423 | if (!cinfo->fbmem) { | 2425 | if (!info->screen_base) { |
2424 | ret = -EIO; | 2426 | ret = -EIO; |
2425 | goto err_release_legacy; | 2427 | goto err_release_legacy; |
2426 | } | 2428 | } |
2427 | 2429 | ||
2428 | cinfo->fbmem_phys = board_addr; | 2430 | info->fix.smem_start = board_addr; |
2429 | cinfo->size = board_size; | 2431 | info->screen_size = board_size; |
2430 | cinfo->unmap = cirrusfb_pci_unmap; | 2432 | cinfo->unmap = cirrusfb_pci_unmap; |
2431 | 2433 | ||
2432 | printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr); | 2434 | printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ", |
2433 | printk ("Cirrus Logic chipset on PCI bus\n"); | 2435 | info->screen_size >> 10, board_addr); |
2436 | printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n"); | ||
2434 | pci_set_drvdata(pdev, info); | 2437 | pci_set_drvdata(pdev, info); |
2435 | 2438 | ||
2436 | ret = cirrusfb_register(cinfo); | 2439 | ret = cirrusfb_register(info); |
2437 | if (ret) | 2440 | if (ret) |
2438 | iounmap(cinfo->fbmem); | 2441 | iounmap(info->screen_base); |
2439 | return ret; | 2442 | return ret; |
2440 | 2443 | ||
2441 | err_release_legacy: | 2444 | err_release_legacy: |
@@ -2453,14 +2456,14 @@ err_out: | |||
2453 | return ret; | 2456 | return ret; |
2454 | } | 2457 | } |
2455 | 2458 | ||
2456 | static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev) | 2459 | static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev) |
2457 | { | 2460 | { |
2458 | struct fb_info *info = pci_get_drvdata(pdev); | 2461 | struct fb_info *info = pci_get_drvdata(pdev); |
2459 | DPRINTK ("ENTER\n"); | 2462 | DPRINTK("ENTER\n"); |
2460 | 2463 | ||
2461 | cirrusfb_cleanup (info); | 2464 | cirrusfb_cleanup(info); |
2462 | 2465 | ||
2463 | DPRINTK ("EXIT\n"); | 2466 | DPRINTK("EXIT\n"); |
2464 | } | 2467 | } |
2465 | 2468 | ||
2466 | static struct pci_driver cirrusfb_pci_driver = { | 2469 | static struct pci_driver cirrusfb_pci_driver = { |
@@ -2477,14 +2480,13 @@ static struct pci_driver cirrusfb_pci_driver = { | |||
2477 | }; | 2480 | }; |
2478 | #endif /* CONFIG_PCI */ | 2481 | #endif /* CONFIG_PCI */ |
2479 | 2482 | ||
2480 | |||
2481 | #ifdef CONFIG_ZORRO | 2483 | #ifdef CONFIG_ZORRO |
2482 | static int cirrusfb_zorro_register(struct zorro_dev *z, | 2484 | static int cirrusfb_zorro_register(struct zorro_dev *z, |
2483 | const struct zorro_device_id *ent) | 2485 | const struct zorro_device_id *ent) |
2484 | { | 2486 | { |
2485 | struct cirrusfb_info *cinfo; | 2487 | struct cirrusfb_info *cinfo; |
2486 | struct fb_info *info; | 2488 | struct fb_info *info; |
2487 | cirrusfb_board_t btype; | 2489 | enum cirrus_board btype; |
2488 | struct zorro_dev *z2 = NULL; | 2490 | struct zorro_dev *z2 = NULL; |
2489 | unsigned long board_addr, board_size, size; | 2491 | unsigned long board_addr, board_size, size; |
2490 | int ret; | 2492 | int ret; |
@@ -2498,83 +2500,86 @@ static int cirrusfb_zorro_register(struct zorro_dev *z, | |||
2498 | 2500 | ||
2499 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); | 2501 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); |
2500 | if (!info) { | 2502 | if (!info) { |
2501 | printk (KERN_ERR "cirrusfb: could not allocate memory\n"); | 2503 | printk(KERN_ERR "cirrusfb: could not allocate memory\n"); |
2502 | ret = -ENOMEM; | 2504 | ret = -ENOMEM; |
2503 | goto err_out; | 2505 | goto err_out; |
2504 | } | 2506 | } |
2505 | 2507 | ||
2506 | cinfo = info->par; | 2508 | cinfo = info->par; |
2507 | cinfo->info = info; | ||
2508 | cinfo->btype = btype; | 2509 | cinfo->btype = btype; |
2509 | 2510 | ||
2510 | assert (z > 0); | 2511 | assert(z > 0); |
2511 | assert (z2 >= 0); | 2512 | assert(z2 >= 0); |
2512 | assert (btype != BT_NONE); | 2513 | assert(btype != BT_NONE); |
2513 | 2514 | ||
2514 | cinfo->zdev = z; | 2515 | cinfo->zdev = z; |
2515 | board_addr = zorro_resource_start(z); | 2516 | board_addr = zorro_resource_start(z); |
2516 | board_size = zorro_resource_len(z); | 2517 | board_size = zorro_resource_len(z); |
2517 | cinfo->size = size; | 2518 | info->screen_size = size; |
2518 | 2519 | ||
2519 | if (!zorro_request_device(z, "cirrusfb")) { | 2520 | if (!zorro_request_device(z, "cirrusfb")) { |
2520 | printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", | 2521 | printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " |
2522 | "abort\n", | ||
2521 | board_addr); | 2523 | board_addr); |
2522 | ret = -EBUSY; | 2524 | ret = -EBUSY; |
2523 | goto err_release_fb; | 2525 | goto err_release_fb; |
2524 | } | 2526 | } |
2525 | 2527 | ||
2526 | printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); | 2528 | printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); |
2527 | 2529 | ||
2528 | ret = -EIO; | 2530 | ret = -EIO; |
2529 | 2531 | ||
2530 | if (btype == BT_PICASSO4) { | 2532 | if (btype == BT_PICASSO4) { |
2531 | printk (" REG at $%lx\n", board_addr + 0x600000); | 2533 | printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000); |
2532 | 2534 | ||
2533 | /* To be precise, for the P4 this is not the */ | 2535 | /* To be precise, for the P4 this is not the */ |
2534 | /* begin of the board, but the begin of RAM. */ | 2536 | /* begin of the board, but the begin of RAM. */ |
2535 | /* for P4, map in its address space in 2 chunks (### TEST! ) */ | 2537 | /* for P4, map in its address space in 2 chunks (### TEST! ) */ |
2536 | /* (note the ugly hardcoded 16M number) */ | 2538 | /* (note the ugly hardcoded 16M number) */ |
2537 | cinfo->regbase = ioremap (board_addr, 16777216); | 2539 | cinfo->regbase = ioremap(board_addr, 16777216); |
2538 | if (!cinfo->regbase) | 2540 | if (!cinfo->regbase) |
2539 | goto err_release_region; | 2541 | goto err_release_region; |
2540 | 2542 | ||
2541 | DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); | 2543 | DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", |
2544 | cinfo->regbase); | ||
2542 | cinfo->regbase += 0x600000; | 2545 | cinfo->regbase += 0x600000; |
2543 | cinfo->fbregs_phys = board_addr + 0x600000; | 2546 | info->fix.mmio_start = board_addr + 0x600000; |
2544 | 2547 | ||
2545 | cinfo->fbmem_phys = board_addr + 16777216; | 2548 | info->fix.smem_start = board_addr + 16777216; |
2546 | cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216); | 2549 | info->screen_base = ioremap(info->fix.smem_start, 16777216); |
2547 | if (!cinfo->fbmem) | 2550 | if (!info->screen_base) |
2548 | goto err_unmap_regbase; | 2551 | goto err_unmap_regbase; |
2549 | } else { | 2552 | } else { |
2550 | printk (" REG at $%lx\n", (unsigned long) z2->resource.start); | 2553 | printk(KERN_INFO " REG at $%lx\n", |
2554 | (unsigned long) z2->resource.start); | ||
2551 | 2555 | ||
2552 | cinfo->fbmem_phys = board_addr; | 2556 | info->fix.smem_start = board_addr; |
2553 | if (board_addr > 0x01000000) | 2557 | if (board_addr > 0x01000000) |
2554 | cinfo->fbmem = ioremap (board_addr, board_size); | 2558 | info->screen_base = ioremap(board_addr, board_size); |
2555 | else | 2559 | else |
2556 | cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr); | 2560 | info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); |
2557 | if (!cinfo->fbmem) | 2561 | if (!info->screen_base) |
2558 | goto err_release_region; | 2562 | goto err_release_region; |
2559 | 2563 | ||
2560 | /* set address for REG area of board */ | 2564 | /* set address for REG area of board */ |
2561 | cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start); | 2565 | cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); |
2562 | cinfo->fbregs_phys = z2->resource.start; | 2566 | info->fix.mmio_start = z2->resource.start; |
2563 | 2567 | ||
2564 | DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); | 2568 | DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", |
2569 | cinfo->regbase); | ||
2565 | } | 2570 | } |
2566 | cinfo->unmap = cirrusfb_zorro_unmap; | 2571 | cinfo->unmap = cirrusfb_zorro_unmap; |
2567 | 2572 | ||
2568 | printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); | 2573 | printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); |
2569 | zorro_set_drvdata(z, info); | 2574 | zorro_set_drvdata(z, info); |
2570 | 2575 | ||
2571 | ret = cirrusfb_register(cinfo); | 2576 | ret = cirrusfb_register(cinfo); |
2572 | if (ret) { | 2577 | if (ret) { |
2573 | if (btype == BT_PICASSO4) { | 2578 | if (btype == BT_PICASSO4) { |
2574 | iounmap(cinfo->fbmem); | 2579 | iounmap(info->screen_base); |
2575 | iounmap(cinfo->regbase - 0x600000); | 2580 | iounmap(cinfo->regbase - 0x600000); |
2576 | } else if (board_addr > 0x01000000) | 2581 | } else if (board_addr > 0x01000000) |
2577 | iounmap(cinfo->fbmem); | 2582 | iounmap(info->screen_base); |
2578 | } | 2583 | } |
2579 | return ret; | 2584 | return ret; |
2580 | 2585 | ||
@@ -2592,11 +2597,11 @@ err_out: | |||
2592 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) | 2597 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) |
2593 | { | 2598 | { |
2594 | struct fb_info *info = zorro_get_drvdata(z); | 2599 | struct fb_info *info = zorro_get_drvdata(z); |
2595 | DPRINTK ("ENTER\n"); | 2600 | DPRINTK("ENTER\n"); |
2596 | 2601 | ||
2597 | cirrusfb_cleanup (info); | 2602 | cirrusfb_cleanup(info); |
2598 | 2603 | ||
2599 | DPRINTK ("EXIT\n"); | 2604 | DPRINTK("EXIT\n"); |
2600 | } | 2605 | } |
2601 | 2606 | ||
2602 | static struct zorro_driver cirrusfb_zorro_driver = { | 2607 | static struct zorro_driver cirrusfb_zorro_driver = { |
@@ -2628,26 +2633,24 @@ static int __init cirrusfb_init(void) | |||
2628 | return error; | 2633 | return error; |
2629 | } | 2634 | } |
2630 | 2635 | ||
2631 | |||
2632 | |||
2633 | #ifndef MODULE | 2636 | #ifndef MODULE |
2634 | static int __init cirrusfb_setup(char *options) { | 2637 | static int __init cirrusfb_setup(char *options) { |
2635 | char *this_opt, s[32]; | 2638 | char *this_opt, s[32]; |
2636 | int i; | 2639 | int i; |
2637 | 2640 | ||
2638 | DPRINTK ("ENTER\n"); | 2641 | DPRINTK("ENTER\n"); |
2639 | 2642 | ||
2640 | if (!options || !*options) | 2643 | if (!options || !*options) |
2641 | return 0; | 2644 | return 0; |
2642 | 2645 | ||
2643 | while ((this_opt = strsep (&options, ",")) != NULL) { | 2646 | while ((this_opt = strsep(&options, ",")) != NULL) { |
2644 | if (!*this_opt) continue; | 2647 | if (!*this_opt) continue; |
2645 | 2648 | ||
2646 | DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); | 2649 | DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); |
2647 | 2650 | ||
2648 | for (i = 0; i < NUM_TOTAL_MODES; i++) { | 2651 | for (i = 0; i < NUM_TOTAL_MODES; i++) { |
2649 | sprintf (s, "mode:%s", cirrusfb_predefined[i].name); | 2652 | sprintf(s, "mode:%s", cirrusfb_predefined[i].name); |
2650 | if (strcmp (this_opt, s) == 0) | 2653 | if (strcmp(this_opt, s) == 0) |
2651 | cirrusfb_def_mode = i; | 2654 | cirrusfb_def_mode = i; |
2652 | } | 2655 | } |
2653 | if (!strcmp(this_opt, "noaccel")) | 2656 | if (!strcmp(this_opt, "noaccel")) |
@@ -2657,7 +2660,6 @@ static int __init cirrusfb_setup(char *options) { | |||
2657 | } | 2660 | } |
2658 | #endif | 2661 | #endif |
2659 | 2662 | ||
2660 | |||
2661 | /* | 2663 | /* |
2662 | * Modularization | 2664 | * Modularization |
2663 | */ | 2665 | */ |
@@ -2666,7 +2668,7 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>"); | |||
2666 | MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); | 2668 | MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); |
2667 | MODULE_LICENSE("GPL"); | 2669 | MODULE_LICENSE("GPL"); |
2668 | 2670 | ||
2669 | static void __exit cirrusfb_exit (void) | 2671 | static void __exit cirrusfb_exit(void) |
2670 | { | 2672 | { |
2671 | #ifdef CONFIG_PCI | 2673 | #ifdef CONFIG_PCI |
2672 | pci_unregister_driver(&cirrusfb_pci_driver); | 2674 | pci_unregister_driver(&cirrusfb_pci_driver); |
@@ -2682,66 +2684,67 @@ module_init(cirrusfb_init); | |||
2682 | module_exit(cirrusfb_exit); | 2684 | module_exit(cirrusfb_exit); |
2683 | #endif | 2685 | #endif |
2684 | 2686 | ||
2685 | |||
2686 | /**********************************************************************/ | 2687 | /**********************************************************************/ |
2687 | /* about the following functions - I have used the same names for the */ | 2688 | /* about the following functions - I have used the same names for the */ |
2688 | /* functions as Markus Wild did in his Retina driver for NetBSD as */ | 2689 | /* functions as Markus Wild did in his Retina driver for NetBSD as */ |
2689 | /* they just made sense for this purpose. Apart from that, I wrote */ | 2690 | /* they just made sense for this purpose. Apart from that, I wrote */ |
2690 | /* these functions myself. */ | 2691 | /* these functions myself. */ |
2691 | /**********************************************************************/ | 2692 | /**********************************************************************/ |
2692 | 2693 | ||
2693 | /*** WGen() - write into one of the external/general registers ***/ | 2694 | /*** WGen() - write into one of the external/general registers ***/ |
2694 | static void WGen (const struct cirrusfb_info *cinfo, | 2695 | static void WGen(const struct cirrusfb_info *cinfo, |
2695 | int regnum, unsigned char val) | 2696 | int regnum, unsigned char val) |
2696 | { | 2697 | { |
2697 | unsigned long regofs = 0; | 2698 | unsigned long regofs = 0; |
2698 | 2699 | ||
2699 | if (cinfo->btype == BT_PICASSO) { | 2700 | if (cinfo->btype == BT_PICASSO) { |
2700 | /* Picasso II specific hack */ | 2701 | /* Picasso II specific hack */ |
2701 | /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ | 2702 | /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || |
2703 | regnum == CL_VSSM2) */ | ||
2702 | if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) | 2704 | if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) |
2703 | regofs = 0xfff; | 2705 | regofs = 0xfff; |
2704 | } | 2706 | } |
2705 | 2707 | ||
2706 | vga_w (cinfo->regbase, regofs + regnum, val); | 2708 | vga_w(cinfo->regbase, regofs + regnum, val); |
2707 | } | 2709 | } |
2708 | 2710 | ||
2709 | /*** RGen() - read out one of the external/general registers ***/ | 2711 | /*** RGen() - read out one of the external/general registers ***/ |
2710 | static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum) | 2712 | static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum) |
2711 | { | 2713 | { |
2712 | unsigned long regofs = 0; | 2714 | unsigned long regofs = 0; |
2713 | 2715 | ||
2714 | if (cinfo->btype == BT_PICASSO) { | 2716 | if (cinfo->btype == BT_PICASSO) { |
2715 | /* Picasso II specific hack */ | 2717 | /* Picasso II specific hack */ |
2716 | /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ | 2718 | /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || |
2719 | regnum == CL_VSSM2) */ | ||
2717 | if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) | 2720 | if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) |
2718 | regofs = 0xfff; | 2721 | regofs = 0xfff; |
2719 | } | 2722 | } |
2720 | 2723 | ||
2721 | return vga_r (cinfo->regbase, regofs + regnum); | 2724 | return vga_r(cinfo->regbase, regofs + regnum); |
2722 | } | 2725 | } |
2723 | 2726 | ||
2724 | /*** AttrOn() - turn on VideoEnable for Attribute controller ***/ | 2727 | /*** AttrOn() - turn on VideoEnable for Attribute controller ***/ |
2725 | static void AttrOn (const struct cirrusfb_info *cinfo) | 2728 | static void AttrOn(const struct cirrusfb_info *cinfo) |
2726 | { | 2729 | { |
2727 | assert (cinfo != NULL); | 2730 | assert(cinfo != NULL); |
2728 | 2731 | ||
2729 | DPRINTK ("ENTER\n"); | 2732 | DPRINTK("ENTER\n"); |
2730 | 2733 | ||
2731 | if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) { | 2734 | if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) { |
2732 | /* if we're just in "write value" mode, write back the */ | 2735 | /* if we're just in "write value" mode, write back the */ |
2733 | /* same value as before to not modify anything */ | 2736 | /* same value as before to not modify anything */ |
2734 | vga_w (cinfo->regbase, VGA_ATT_IW, | 2737 | vga_w(cinfo->regbase, VGA_ATT_IW, |
2735 | vga_r (cinfo->regbase, VGA_ATT_R)); | 2738 | vga_r(cinfo->regbase, VGA_ATT_R)); |
2736 | } | 2739 | } |
2737 | /* turn on video bit */ | 2740 | /* turn on video bit */ |
2738 | /* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */ | 2741 | /* vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */ |
2739 | vga_w (cinfo->regbase, VGA_ATT_IW, 0x33); | 2742 | vga_w(cinfo->regbase, VGA_ATT_IW, 0x33); |
2740 | 2743 | ||
2741 | /* dummy write on Reg0 to be on "write index" mode next time */ | 2744 | /* dummy write on Reg0 to be on "write index" mode next time */ |
2742 | vga_w (cinfo->regbase, VGA_ATT_IW, 0x00); | 2745 | vga_w(cinfo->regbase, VGA_ATT_IW, 0x00); |
2743 | 2746 | ||
2744 | DPRINTK ("EXIT\n"); | 2747 | DPRINTK("EXIT\n"); |
2745 | } | 2748 | } |
2746 | 2749 | ||
2747 | /*** WHDR() - write into the Hidden DAC register ***/ | 2750 | /*** WHDR() - write into the Hidden DAC register ***/ |
@@ -2750,119 +2753,115 @@ static void AttrOn (const struct cirrusfb_info *cinfo) | |||
2750 | * registers of their functional group) here is a specialized routine for | 2753 | * registers of their functional group) here is a specialized routine for |
2751 | * accessing the HDR | 2754 | * accessing the HDR |
2752 | */ | 2755 | */ |
2753 | static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val) | 2756 | static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val) |
2754 | { | 2757 | { |
2755 | unsigned char dummy; | 2758 | unsigned char dummy; |
2756 | 2759 | ||
2757 | if (cinfo->btype == BT_PICASSO) { | 2760 | if (cinfo->btype == BT_PICASSO) { |
2758 | /* Klaus' hint for correct access to HDR on some boards */ | 2761 | /* Klaus' hint for correct access to HDR on some boards */ |
2759 | /* first write 0 to pixel mask (3c6) */ | 2762 | /* first write 0 to pixel mask (3c6) */ |
2760 | WGen (cinfo, VGA_PEL_MSK, 0x00); | 2763 | WGen(cinfo, VGA_PEL_MSK, 0x00); |
2761 | udelay (200); | 2764 | udelay(200); |
2762 | /* next read dummy from pixel address (3c8) */ | 2765 | /* next read dummy from pixel address (3c8) */ |
2763 | dummy = RGen (cinfo, VGA_PEL_IW); | 2766 | dummy = RGen(cinfo, VGA_PEL_IW); |
2764 | udelay (200); | 2767 | udelay(200); |
2765 | } | 2768 | } |
2766 | /* now do the usual stuff to access the HDR */ | 2769 | /* now do the usual stuff to access the HDR */ |
2767 | 2770 | ||
2768 | dummy = RGen (cinfo, VGA_PEL_MSK); | 2771 | dummy = RGen(cinfo, VGA_PEL_MSK); |
2769 | udelay (200); | 2772 | udelay(200); |
2770 | dummy = RGen (cinfo, VGA_PEL_MSK); | 2773 | dummy = RGen(cinfo, VGA_PEL_MSK); |
2771 | udelay (200); | 2774 | udelay(200); |
2772 | dummy = RGen (cinfo, VGA_PEL_MSK); | 2775 | dummy = RGen(cinfo, VGA_PEL_MSK); |
2773 | udelay (200); | 2776 | udelay(200); |
2774 | dummy = RGen (cinfo, VGA_PEL_MSK); | 2777 | dummy = RGen(cinfo, VGA_PEL_MSK); |
2775 | udelay (200); | 2778 | udelay(200); |
2776 | 2779 | ||
2777 | WGen (cinfo, VGA_PEL_MSK, val); | 2780 | WGen(cinfo, VGA_PEL_MSK, val); |
2778 | udelay (200); | 2781 | udelay(200); |
2779 | 2782 | ||
2780 | if (cinfo->btype == BT_PICASSO) { | 2783 | if (cinfo->btype == BT_PICASSO) { |
2781 | /* now first reset HDR access counter */ | 2784 | /* now first reset HDR access counter */ |
2782 | dummy = RGen (cinfo, VGA_PEL_IW); | 2785 | dummy = RGen(cinfo, VGA_PEL_IW); |
2783 | udelay (200); | 2786 | udelay(200); |
2784 | 2787 | ||
2785 | /* and at the end, restore the mask value */ | 2788 | /* and at the end, restore the mask value */ |
2786 | /* ## is this mask always 0xff? */ | 2789 | /* ## is this mask always 0xff? */ |
2787 | WGen (cinfo, VGA_PEL_MSK, 0xff); | 2790 | WGen(cinfo, VGA_PEL_MSK, 0xff); |
2788 | udelay (200); | 2791 | udelay(200); |
2789 | } | 2792 | } |
2790 | } | 2793 | } |
2791 | 2794 | ||
2792 | |||
2793 | /*** WSFR() - write to the "special function register" (SFR) ***/ | 2795 | /*** WSFR() - write to the "special function register" (SFR) ***/ |
2794 | static void WSFR (struct cirrusfb_info *cinfo, unsigned char val) | 2796 | static void WSFR(struct cirrusfb_info *cinfo, unsigned char val) |
2795 | { | 2797 | { |
2796 | #ifdef CONFIG_ZORRO | 2798 | #ifdef CONFIG_ZORRO |
2797 | assert (cinfo->regbase != NULL); | 2799 | assert(cinfo->regbase != NULL); |
2798 | cinfo->SFR = val; | 2800 | cinfo->SFR = val; |
2799 | z_writeb (val, cinfo->regbase + 0x8000); | 2801 | z_writeb(val, cinfo->regbase + 0x8000); |
2800 | #endif | 2802 | #endif |
2801 | } | 2803 | } |
2802 | 2804 | ||
2803 | /* The Picasso has a second register for switching the monitor bit */ | 2805 | /* The Picasso has a second register for switching the monitor bit */ |
2804 | static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val) | 2806 | static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val) |
2805 | { | 2807 | { |
2806 | #ifdef CONFIG_ZORRO | 2808 | #ifdef CONFIG_ZORRO |
2807 | /* writing an arbitrary value to this one causes the monitor switcher */ | 2809 | /* writing an arbitrary value to this one causes the monitor switcher */ |
2808 | /* to flip to Amiga display */ | 2810 | /* to flip to Amiga display */ |
2809 | assert (cinfo->regbase != NULL); | 2811 | assert(cinfo->regbase != NULL); |
2810 | cinfo->SFR = val; | 2812 | cinfo->SFR = val; |
2811 | z_writeb (val, cinfo->regbase + 0x9000); | 2813 | z_writeb(val, cinfo->regbase + 0x9000); |
2812 | #endif | 2814 | #endif |
2813 | } | 2815 | } |
2814 | 2816 | ||
2815 | |||
2816 | /*** WClut - set CLUT entry (range: 0..63) ***/ | 2817 | /*** WClut - set CLUT entry (range: 0..63) ***/ |
2817 | static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, | 2818 | static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, |
2818 | unsigned char green, unsigned char blue) | 2819 | unsigned char green, unsigned char blue) |
2819 | { | 2820 | { |
2820 | unsigned int data = VGA_PEL_D; | 2821 | unsigned int data = VGA_PEL_D; |
2821 | 2822 | ||
2822 | /* address write mode register is not translated.. */ | 2823 | /* address write mode register is not translated.. */ |
2823 | vga_w (cinfo->regbase, VGA_PEL_IW, regnum); | 2824 | vga_w(cinfo->regbase, VGA_PEL_IW, regnum); |
2824 | 2825 | ||
2825 | if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || | 2826 | if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || |
2826 | cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { | 2827 | cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { |
2827 | /* but DAC data register IS, at least for Picasso II */ | 2828 | /* but DAC data register IS, at least for Picasso II */ |
2828 | if (cinfo->btype == BT_PICASSO) | 2829 | if (cinfo->btype == BT_PICASSO) |
2829 | data += 0xfff; | 2830 | data += 0xfff; |
2830 | vga_w (cinfo->regbase, data, red); | 2831 | vga_w(cinfo->regbase, data, red); |
2831 | vga_w (cinfo->regbase, data, green); | 2832 | vga_w(cinfo->regbase, data, green); |
2832 | vga_w (cinfo->regbase, data, blue); | 2833 | vga_w(cinfo->regbase, data, blue); |
2833 | } else { | 2834 | } else { |
2834 | vga_w (cinfo->regbase, data, blue); | 2835 | vga_w(cinfo->regbase, data, blue); |
2835 | vga_w (cinfo->regbase, data, green); | 2836 | vga_w(cinfo->regbase, data, green); |
2836 | vga_w (cinfo->regbase, data, red); | 2837 | vga_w(cinfo->regbase, data, red); |
2837 | } | 2838 | } |
2838 | } | 2839 | } |
2839 | 2840 | ||
2840 | |||
2841 | #if 0 | 2841 | #if 0 |
2842 | /*** RClut - read CLUT entry (range 0..63) ***/ | 2842 | /*** RClut - read CLUT entry (range 0..63) ***/ |
2843 | static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, | 2843 | static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, |
2844 | unsigned char *green, unsigned char *blue) | 2844 | unsigned char *green, unsigned char *blue) |
2845 | { | 2845 | { |
2846 | unsigned int data = VGA_PEL_D; | 2846 | unsigned int data = VGA_PEL_D; |
2847 | 2847 | ||
2848 | vga_w (cinfo->regbase, VGA_PEL_IR, regnum); | 2848 | vga_w(cinfo->regbase, VGA_PEL_IR, regnum); |
2849 | 2849 | ||
2850 | if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || | 2850 | if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || |
2851 | cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { | 2851 | cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { |
2852 | if (cinfo->btype == BT_PICASSO) | 2852 | if (cinfo->btype == BT_PICASSO) |
2853 | data += 0xfff; | 2853 | data += 0xfff; |
2854 | *red = vga_r (cinfo->regbase, data); | 2854 | *red = vga_r(cinfo->regbase, data); |
2855 | *green = vga_r (cinfo->regbase, data); | 2855 | *green = vga_r(cinfo->regbase, data); |
2856 | *blue = vga_r (cinfo->regbase, data); | 2856 | *blue = vga_r(cinfo->regbase, data); |
2857 | } else { | 2857 | } else { |
2858 | *blue = vga_r (cinfo->regbase, data); | 2858 | *blue = vga_r(cinfo->regbase, data); |
2859 | *green = vga_r (cinfo->regbase, data); | 2859 | *green = vga_r(cinfo->regbase, data); |
2860 | *red = vga_r (cinfo->regbase, data); | 2860 | *red = vga_r(cinfo->regbase, data); |
2861 | } | 2861 | } |
2862 | } | 2862 | } |
2863 | #endif | 2863 | #endif |
2864 | 2864 | ||
2865 | |||
2866 | /******************************************************************* | 2865 | /******************************************************************* |
2867 | cirrusfb_WaitBLT() | 2866 | cirrusfb_WaitBLT() |
2868 | 2867 | ||
@@ -2870,10 +2869,10 @@ static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned c | |||
2870 | *********************************************************************/ | 2869 | *********************************************************************/ |
2871 | 2870 | ||
2872 | /* FIXME: use interrupts instead */ | 2871 | /* FIXME: use interrupts instead */ |
2873 | static void cirrusfb_WaitBLT (u8 __iomem *regbase) | 2872 | static void cirrusfb_WaitBLT(u8 __iomem *regbase) |
2874 | { | 2873 | { |
2875 | /* now busy-wait until we're done */ | 2874 | /* now busy-wait until we're done */ |
2876 | while (vga_rgfx (regbase, CL_GR31) & 0x08) | 2875 | while (vga_rgfx(regbase, CL_GR31) & 0x08) |
2877 | /* do nothing */ ; | 2876 | /* do nothing */ ; |
2878 | } | 2877 | } |
2879 | 2878 | ||
@@ -2883,15 +2882,17 @@ static void cirrusfb_WaitBLT (u8 __iomem *regbase) | |||
2883 | perform accelerated "scrolling" | 2882 | perform accelerated "scrolling" |
2884 | ********************************************************************/ | 2883 | ********************************************************************/ |
2885 | 2884 | ||
2886 | static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, | 2885 | static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, |
2887 | u_short curx, u_short cury, u_short destx, u_short desty, | 2886 | u_short curx, u_short cury, |
2888 | u_short width, u_short height, u_short line_length) | 2887 | u_short destx, u_short desty, |
2888 | u_short width, u_short height, | ||
2889 | u_short line_length) | ||
2889 | { | 2890 | { |
2890 | u_short nwidth, nheight; | 2891 | u_short nwidth, nheight; |
2891 | u_long nsrc, ndest; | 2892 | u_long nsrc, ndest; |
2892 | u_char bltmode; | 2893 | u_char bltmode; |
2893 | 2894 | ||
2894 | DPRINTK ("ENTER\n"); | 2895 | DPRINTK("ENTER\n"); |
2895 | 2896 | ||
2896 | nwidth = width - 1; | 2897 | nwidth = width - 1; |
2897 | nheight = height - 1; | 2898 | nheight = height - 1; |
@@ -2911,9 +2912,13 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, | |||
2911 | nsrc = (cury * line_length) + curx; | 2912 | nsrc = (cury * line_length) + curx; |
2912 | ndest = (desty * line_length) + destx; | 2913 | ndest = (desty * line_length) + destx; |
2913 | } else { | 2914 | } else { |
2914 | /* this means start addresses are at the end, counting backwards */ | 2915 | /* this means start addresses are at the end, |
2915 | nsrc = cury * line_length + curx + nheight * line_length + nwidth; | 2916 | * counting backwards |
2916 | ndest = desty * line_length + destx + nheight * line_length + nwidth; | 2917 | */ |
2918 | nsrc = cury * line_length + curx + | ||
2919 | nheight * line_length + nwidth; | ||
2920 | ndest = desty * line_length + destx + | ||
2921 | nheight * line_length + nwidth; | ||
2917 | } | 2922 | } |
2918 | 2923 | ||
2919 | /* | 2924 | /* |
@@ -2929,52 +2934,65 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, | |||
2929 | start/stop | 2934 | start/stop |
2930 | */ | 2935 | */ |
2931 | 2936 | ||
2932 | cirrusfb_WaitBLT(regbase); | 2937 | cirrusfb_WaitBLT(regbase); |
2933 | 2938 | ||
2934 | /* pitch: set to line_length */ | 2939 | /* pitch: set to line_length */ |
2935 | vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ | 2940 | /* dest pitch low */ |
2936 | vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ | 2941 | vga_wgfx(regbase, CL_GR24, line_length & 0xff); |
2937 | vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ | 2942 | /* dest pitch hi */ |
2938 | vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ | 2943 | vga_wgfx(regbase, CL_GR25, line_length >> 8); |
2944 | /* source pitch low */ | ||
2945 | vga_wgfx(regbase, CL_GR26, line_length & 0xff); | ||
2946 | /* source pitch hi */ | ||
2947 | vga_wgfx(regbase, CL_GR27, line_length >> 8); | ||
2939 | 2948 | ||
2940 | /* BLT width: actual number of pixels - 1 */ | 2949 | /* BLT width: actual number of pixels - 1 */ |
2941 | vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ | 2950 | /* BLT width low */ |
2942 | vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ | 2951 | vga_wgfx(regbase, CL_GR20, nwidth & 0xff); |
2952 | /* BLT width hi */ | ||
2953 | vga_wgfx(regbase, CL_GR21, nwidth >> 8); | ||
2943 | 2954 | ||
2944 | /* BLT height: actual number of lines -1 */ | 2955 | /* BLT height: actual number of lines -1 */ |
2945 | vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ | 2956 | /* BLT height low */ |
2946 | vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ | 2957 | vga_wgfx(regbase, CL_GR22, nheight & 0xff); |
2958 | /* BLT width hi */ | ||
2959 | vga_wgfx(regbase, CL_GR23, nheight >> 8); | ||
2947 | 2960 | ||
2948 | /* BLT destination */ | 2961 | /* BLT destination */ |
2949 | vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ | 2962 | /* BLT dest low */ |
2950 | vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ | 2963 | vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); |
2951 | vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ | 2964 | /* BLT dest mid */ |
2965 | vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); | ||
2966 | /* BLT dest hi */ | ||
2967 | vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); | ||
2952 | 2968 | ||
2953 | /* BLT source */ | 2969 | /* BLT source */ |
2954 | vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */ | 2970 | /* BLT src low */ |
2955 | vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */ | 2971 | vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff)); |
2956 | vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */ | 2972 | /* BLT src mid */ |
2973 | vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8)); | ||
2974 | /* BLT src hi */ | ||
2975 | vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16)); | ||
2957 | 2976 | ||
2958 | /* BLT mode */ | 2977 | /* BLT mode */ |
2959 | vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */ | 2978 | vga_wgfx(regbase, CL_GR30, bltmode); /* BLT mode */ |
2960 | 2979 | ||
2961 | /* BLT ROP: SrcCopy */ | 2980 | /* BLT ROP: SrcCopy */ |
2962 | vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ | 2981 | vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ |
2963 | 2982 | ||
2964 | /* and finally: GO! */ | 2983 | /* and finally: GO! */ |
2965 | vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ | 2984 | vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ |
2966 | 2985 | ||
2967 | DPRINTK ("EXIT\n"); | 2986 | DPRINTK("EXIT\n"); |
2968 | } | 2987 | } |
2969 | 2988 | ||
2970 | |||
2971 | /******************************************************************* | 2989 | /******************************************************************* |
2972 | cirrusfb_RectFill() | 2990 | cirrusfb_RectFill() |
2973 | 2991 | ||
2974 | perform accelerated rectangle fill | 2992 | perform accelerated rectangle fill |
2975 | ********************************************************************/ | 2993 | ********************************************************************/ |
2976 | 2994 | ||
2977 | static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, | 2995 | static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, |
2978 | u_short x, u_short y, u_short width, u_short height, | 2996 | u_short x, u_short y, u_short width, u_short height, |
2979 | u_char color, u_short line_length) | 2997 | u_char color, u_short line_length) |
2980 | { | 2998 | { |
@@ -2982,93 +3000,95 @@ static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, | |||
2982 | u_long ndest; | 3000 | u_long ndest; |
2983 | u_char op; | 3001 | u_char op; |
2984 | 3002 | ||
2985 | DPRINTK ("ENTER\n"); | 3003 | DPRINTK("ENTER\n"); |
2986 | 3004 | ||
2987 | nwidth = width - 1; | 3005 | nwidth = width - 1; |
2988 | nheight = height - 1; | 3006 | nheight = height - 1; |
2989 | 3007 | ||
2990 | ndest = (y * line_length) + x; | 3008 | ndest = (y * line_length) + x; |
2991 | 3009 | ||
2992 | cirrusfb_WaitBLT(regbase); | 3010 | cirrusfb_WaitBLT(regbase); |
2993 | 3011 | ||
2994 | /* pitch: set to line_length */ | 3012 | /* pitch: set to line_length */ |
2995 | vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ | 3013 | vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ |
2996 | vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ | 3014 | vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */ |
2997 | vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ | 3015 | vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */ |
2998 | vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ | 3016 | vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */ |
2999 | 3017 | ||
3000 | /* BLT width: actual number of pixels - 1 */ | 3018 | /* BLT width: actual number of pixels - 1 */ |
3001 | vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ | 3019 | vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ |
3002 | vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ | 3020 | vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */ |
3003 | 3021 | ||
3004 | /* BLT height: actual number of lines -1 */ | 3022 | /* BLT height: actual number of lines -1 */ |
3005 | vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ | 3023 | vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */ |
3006 | vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ | 3024 | vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */ |
3007 | 3025 | ||
3008 | /* BLT destination */ | 3026 | /* BLT destination */ |
3009 | vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ | 3027 | /* BLT dest low */ |
3010 | vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ | 3028 | vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); |
3011 | vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ | 3029 | /* BLT dest mid */ |
3030 | vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); | ||
3031 | /* BLT dest hi */ | ||
3032 | vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); | ||
3012 | 3033 | ||
3013 | /* BLT source: set to 0 (is a dummy here anyway) */ | 3034 | /* BLT source: set to 0 (is a dummy here anyway) */ |
3014 | vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */ | 3035 | vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */ |
3015 | vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */ | 3036 | vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */ |
3016 | vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */ | 3037 | vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */ |
3017 | 3038 | ||
3018 | /* This is a ColorExpand Blt, using the */ | 3039 | /* This is a ColorExpand Blt, using the */ |
3019 | /* same color for foreground and background */ | 3040 | /* same color for foreground and background */ |
3020 | vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ | 3041 | vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ |
3021 | vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */ | 3042 | vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */ |
3022 | 3043 | ||
3023 | op = 0xc0; | 3044 | op = 0xc0; |
3024 | if (bits_per_pixel == 16) { | 3045 | if (bits_per_pixel == 16) { |
3025 | vga_wgfx (regbase, CL_GR10, color); /* foreground color */ | 3046 | vga_wgfx(regbase, CL_GR10, color); /* foreground color */ |
3026 | vga_wgfx (regbase, CL_GR11, color); /* background color */ | 3047 | vga_wgfx(regbase, CL_GR11, color); /* background color */ |
3027 | op = 0x50; | 3048 | op = 0x50; |
3028 | op = 0xd0; | 3049 | op = 0xd0; |
3029 | } else if (bits_per_pixel == 32) { | 3050 | } else if (bits_per_pixel == 32) { |
3030 | vga_wgfx (regbase, CL_GR10, color); /* foreground color */ | 3051 | vga_wgfx(regbase, CL_GR10, color); /* foreground color */ |
3031 | vga_wgfx (regbase, CL_GR11, color); /* background color */ | 3052 | vga_wgfx(regbase, CL_GR11, color); /* background color */ |
3032 | vga_wgfx (regbase, CL_GR12, color); /* foreground color */ | 3053 | vga_wgfx(regbase, CL_GR12, color); /* foreground color */ |
3033 | vga_wgfx (regbase, CL_GR13, color); /* background color */ | 3054 | vga_wgfx(regbase, CL_GR13, color); /* background color */ |
3034 | vga_wgfx (regbase, CL_GR14, 0); /* foreground color */ | 3055 | vga_wgfx(regbase, CL_GR14, 0); /* foreground color */ |
3035 | vga_wgfx (regbase, CL_GR15, 0); /* background color */ | 3056 | vga_wgfx(regbase, CL_GR15, 0); /* background color */ |
3036 | op = 0x50; | 3057 | op = 0x50; |
3037 | op = 0xf0; | 3058 | op = 0xf0; |
3038 | } | 3059 | } |
3039 | /* BLT mode: color expand, Enable 8x8 copy (faster?) */ | 3060 | /* BLT mode: color expand, Enable 8x8 copy (faster?) */ |
3040 | vga_wgfx (regbase, CL_GR30, op); /* BLT mode */ | 3061 | vga_wgfx(regbase, CL_GR30, op); /* BLT mode */ |
3041 | 3062 | ||
3042 | /* BLT ROP: SrcCopy */ | 3063 | /* BLT ROP: SrcCopy */ |
3043 | vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ | 3064 | vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ |
3044 | 3065 | ||
3045 | /* and finally: GO! */ | 3066 | /* and finally: GO! */ |
3046 | vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ | 3067 | vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ |
3047 | 3068 | ||
3048 | DPRINTK ("EXIT\n"); | 3069 | DPRINTK("EXIT\n"); |
3049 | } | 3070 | } |
3050 | 3071 | ||
3051 | |||
3052 | /************************************************************************** | 3072 | /************************************************************************** |
3053 | * bestclock() - determine closest possible clock lower(?) than the | 3073 | * bestclock() - determine closest possible clock lower(?) than the |
3054 | * desired pixel clock | 3074 | * desired pixel clock |
3055 | **************************************************************************/ | 3075 | **************************************************************************/ |
3056 | static void bestclock (long freq, long *best, long *nom, | 3076 | static void bestclock(long freq, long *best, long *nom, |
3057 | long *den, long *div, long maxfreq) | 3077 | long *den, long *div, long maxfreq) |
3058 | { | 3078 | { |
3059 | long n, h, d, f; | 3079 | long n, h, d, f; |
3060 | 3080 | ||
3061 | assert (best != NULL); | 3081 | assert(best != NULL); |
3062 | assert (nom != NULL); | 3082 | assert(nom != NULL); |
3063 | assert (den != NULL); | 3083 | assert(den != NULL); |
3064 | assert (div != NULL); | 3084 | assert(div != NULL); |
3065 | assert (maxfreq > 0); | 3085 | assert(maxfreq > 0); |
3066 | 3086 | ||
3067 | *nom = 0; | 3087 | *nom = 0; |
3068 | *den = 0; | 3088 | *den = 0; |
3069 | *div = 0; | 3089 | *div = 0; |
3070 | 3090 | ||
3071 | DPRINTK ("ENTER\n"); | 3091 | DPRINTK("ENTER\n"); |
3072 | 3092 | ||
3073 | if (freq < 8000) | 3093 | if (freq < 8000) |
3074 | freq = 8000; | 3094 | freq = 8000; |
@@ -3085,7 +3105,7 @@ static void bestclock (long freq, long *best, long *nom, | |||
3085 | if (d > 31) | 3105 | if (d > 31) |
3086 | d = (d / 2) * 2; | 3106 | d = (d / 2) * 2; |
3087 | h = (14318 * n) / d; | 3107 | h = (14318 * n) / d; |
3088 | if (abs (h - freq) < abs (*best - freq)) { | 3108 | if (abs(h - freq) < abs(*best - freq)) { |
3089 | *best = h; | 3109 | *best = h; |
3090 | *nom = n; | 3110 | *nom = n; |
3091 | if (d < 32) { | 3111 | if (d < 32) { |
@@ -3102,7 +3122,7 @@ static void bestclock (long freq, long *best, long *nom, | |||
3102 | if (d > 31) | 3122 | if (d > 31) |
3103 | d = (d / 2) * 2; | 3123 | d = (d / 2) * 2; |
3104 | h = (14318 * n) / d; | 3124 | h = (14318 * n) / d; |
3105 | if (abs (h - freq) < abs (*best - freq)) { | 3125 | if (abs(h - freq) < abs(*best - freq)) { |
3106 | *best = h; | 3126 | *best = h; |
3107 | *nom = n; | 3127 | *nom = n; |
3108 | if (d < 32) { | 3128 | if (d < 32) { |
@@ -3116,14 +3136,13 @@ static void bestclock (long freq, long *best, long *nom, | |||
3116 | } | 3136 | } |
3117 | } | 3137 | } |
3118 | 3138 | ||
3119 | DPRINTK ("Best possible values for given frequency:\n"); | 3139 | DPRINTK("Best possible values for given frequency:\n"); |
3120 | DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n", | 3140 | DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n", |
3121 | freq, *nom, *den, *div); | 3141 | freq, *nom, *den, *div); |
3122 | 3142 | ||
3123 | DPRINTK ("EXIT\n"); | 3143 | DPRINTK("EXIT\n"); |
3124 | } | 3144 | } |
3125 | 3145 | ||
3126 | |||
3127 | /* ------------------------------------------------------------------------- | 3146 | /* ------------------------------------------------------------------------- |
3128 | * | 3147 | * |
3129 | * debugging functions | 3148 | * debugging functions |
@@ -3145,21 +3164,20 @@ static void bestclock (long freq, long *best, long *nom, | |||
3145 | */ | 3164 | */ |
3146 | 3165 | ||
3147 | static | 3166 | static |
3148 | void cirrusfb_dbg_print_byte (const char *name, unsigned char val) | 3167 | void cirrusfb_dbg_print_byte(const char *name, unsigned char val) |
3149 | { | 3168 | { |
3150 | DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", | 3169 | DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", |
3151 | name, val, | 3170 | name, val, |
3152 | val & 0x80 ? '1' : '0', | 3171 | val & 0x80 ? '1' : '0', |
3153 | val & 0x40 ? '1' : '0', | 3172 | val & 0x40 ? '1' : '0', |
3154 | val & 0x20 ? '1' : '0', | 3173 | val & 0x20 ? '1' : '0', |
3155 | val & 0x10 ? '1' : '0', | 3174 | val & 0x10 ? '1' : '0', |
3156 | val & 0x08 ? '1' : '0', | 3175 | val & 0x08 ? '1' : '0', |
3157 | val & 0x04 ? '1' : '0', | 3176 | val & 0x04 ? '1' : '0', |
3158 | val & 0x02 ? '1' : '0', | 3177 | val & 0x02 ? '1' : '0', |
3159 | val & 0x01 ? '1' : '0'); | 3178 | val & 0x01 ? '1' : '0'); |
3160 | } | 3179 | } |
3161 | 3180 | ||
3162 | |||
3163 | /** | 3181 | /** |
3164 | * cirrusfb_dbg_print_regs | 3182 | * cirrusfb_dbg_print_regs |
3165 | * @base: If using newmmio, the newmmio base address, otherwise %NULL | 3183 | * @base: If using newmmio, the newmmio base address, otherwise %NULL |
@@ -3172,25 +3190,26 @@ void cirrusfb_dbg_print_byte (const char *name, unsigned char val) | |||
3172 | */ | 3190 | */ |
3173 | 3191 | ||
3174 | static | 3192 | static |
3175 | void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...) | 3193 | void cirrusfb_dbg_print_regs(caddr_t regbase, |
3194 | enum cirrusfb_dbg_reg_class reg_class, ...) | ||
3176 | { | 3195 | { |
3177 | va_list list; | 3196 | va_list list; |
3178 | unsigned char val = 0; | 3197 | unsigned char val = 0; |
3179 | unsigned reg; | 3198 | unsigned reg; |
3180 | char *name; | 3199 | char *name; |
3181 | 3200 | ||
3182 | va_start (list, reg_class); | 3201 | va_start(list, reg_class); |
3183 | 3202 | ||
3184 | name = va_arg (list, char *); | 3203 | name = va_arg(list, char *); |
3185 | while (name != NULL) { | 3204 | while (name != NULL) { |
3186 | reg = va_arg (list, int); | 3205 | reg = va_arg(list, int); |
3187 | 3206 | ||
3188 | switch (reg_class) { | 3207 | switch (reg_class) { |
3189 | case CRT: | 3208 | case CRT: |
3190 | val = vga_rcrt (regbase, (unsigned char) reg); | 3209 | val = vga_rcrt(regbase, (unsigned char) reg); |
3191 | break; | 3210 | break; |
3192 | case SEQ: | 3211 | case SEQ: |
3193 | val = vga_rseq (regbase, (unsigned char) reg); | 3212 | val = vga_rseq(regbase, (unsigned char) reg); |
3194 | break; | 3213 | break; |
3195 | default: | 3214 | default: |
3196 | /* should never occur */ | 3215 | /* should never occur */ |
@@ -3198,15 +3217,14 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas | |||
3198 | break; | 3217 | break; |
3199 | } | 3218 | } |
3200 | 3219 | ||
3201 | cirrusfb_dbg_print_byte (name, val); | 3220 | cirrusfb_dbg_print_byte(name, val); |
3202 | 3221 | ||
3203 | name = va_arg (list, char *); | 3222 | name = va_arg(list, char *); |
3204 | } | 3223 | } |
3205 | 3224 | ||
3206 | va_end (list); | 3225 | va_end(list); |
3207 | } | 3226 | } |
3208 | 3227 | ||
3209 | |||
3210 | /** | 3228 | /** |
3211 | * cirrusfb_dump | 3229 | * cirrusfb_dump |
3212 | * @cirrusfbinfo: | 3230 | * @cirrusfbinfo: |
@@ -3214,13 +3232,11 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas | |||
3214 | * DESCRIPTION: | 3232 | * DESCRIPTION: |
3215 | */ | 3233 | */ |
3216 | 3234 | ||
3217 | static | 3235 | static void cirrusfb_dump(void) |
3218 | void cirrusfb_dump (void) | ||
3219 | { | 3236 | { |
3220 | cirrusfb_dbg_reg_dump (NULL); | 3237 | cirrusfb_dbg_reg_dump(NULL); |
3221 | } | 3238 | } |
3222 | 3239 | ||
3223 | |||
3224 | /** | 3240 | /** |
3225 | * cirrusfb_dbg_reg_dump | 3241 | * cirrusfb_dbg_reg_dump |
3226 | * @base: If using newmmio, the newmmio base address, otherwise %NULL | 3242 | * @base: If using newmmio, the newmmio base address, otherwise %NULL |
@@ -3232,11 +3248,11 @@ void cirrusfb_dump (void) | |||
3232 | */ | 3248 | */ |
3233 | 3249 | ||
3234 | static | 3250 | static |
3235 | void cirrusfb_dbg_reg_dump (caddr_t regbase) | 3251 | void cirrusfb_dbg_reg_dump(caddr_t regbase) |
3236 | { | 3252 | { |
3237 | DPRINTK ("CIRRUSFB VGA CRTC register dump:\n"); | 3253 | DPRINTK("CIRRUSFB VGA CRTC register dump:\n"); |
3238 | 3254 | ||
3239 | cirrusfb_dbg_print_regs (regbase, CRT, | 3255 | cirrusfb_dbg_print_regs(regbase, CRT, |
3240 | "CR00", 0x00, | 3256 | "CR00", 0x00, |
3241 | "CR01", 0x01, | 3257 | "CR01", 0x01, |
3242 | "CR02", 0x02, | 3258 | "CR02", 0x02, |
@@ -3286,11 +3302,11 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase) | |||
3286 | "CR3F", 0x3F, | 3302 | "CR3F", 0x3F, |
3287 | NULL); | 3303 | NULL); |
3288 | 3304 | ||
3289 | DPRINTK ("\n"); | 3305 | DPRINTK("\n"); |
3290 | 3306 | ||
3291 | DPRINTK ("CIRRUSFB VGA SEQ register dump:\n"); | 3307 | DPRINTK("CIRRUSFB VGA SEQ register dump:\n"); |
3292 | 3308 | ||
3293 | cirrusfb_dbg_print_regs (regbase, SEQ, | 3309 | cirrusfb_dbg_print_regs(regbase, SEQ, |
3294 | "SR00", 0x00, | 3310 | "SR00", 0x00, |
3295 | "SR01", 0x01, | 3311 | "SR01", 0x01, |
3296 | "SR02", 0x02, | 3312 | "SR02", 0x02, |
@@ -3319,7 +3335,7 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase) | |||
3319 | "SR1F", 0x1F, | 3335 | "SR1F", 0x1F, |
3320 | NULL); | 3336 | NULL); |
3321 | 3337 | ||
3322 | DPRINTK ("\n"); | 3338 | DPRINTK("\n"); |
3323 | } | 3339 | } |
3324 | 3340 | ||
3325 | #endif /* CIRRUSFB_DEBUG */ | 3341 | #endif /* CIRRUSFB_DEBUG */ |
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index dea6579941b7..17b5267f44d7 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | #include <asm/hardware.h> | 30 | #include <asm/hardware.h> |
31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
32 | #include <asm/uaccess.h> | 32 | #include <linux/uaccess.h> |
33 | 33 | ||
34 | #include <asm/hardware/clps7111.h> | 34 | #include <asm/hardware/clps7111.h> |
35 | #include <asm/arch/syspld.h> | 35 | #include <asm/arch/syspld.h> |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index e58c87b3e3a0..0f32f4a00b2d 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -78,7 +78,6 @@ | |||
78 | #include <asm/fb.h> | 78 | #include <asm/fb.h> |
79 | #include <asm/irq.h> | 79 | #include <asm/irq.h> |
80 | #include <asm/system.h> | 80 | #include <asm/system.h> |
81 | #include <asm/uaccess.h> | ||
82 | #ifdef CONFIG_ATARI | 81 | #ifdef CONFIG_ATARI |
83 | #include <asm/atariints.h> | 82 | #include <asm/atariints.h> |
84 | #endif | 83 | #endif |
@@ -2169,7 +2168,7 @@ static __inline__ void updatescrollmode(struct display *p, | |||
2169 | } | 2168 | } |
2170 | 2169 | ||
2171 | static int fbcon_resize(struct vc_data *vc, unsigned int width, | 2170 | static int fbcon_resize(struct vc_data *vc, unsigned int width, |
2172 | unsigned int height) | 2171 | unsigned int height, unsigned int user) |
2173 | { | 2172 | { |
2174 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 2173 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
2175 | struct fbcon_ops *ops = info->fbcon_par; | 2174 | struct fbcon_ops *ops = info->fbcon_par; |
@@ -2406,7 +2405,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2406 | update_screen(vc); | 2405 | update_screen(vc); |
2407 | } | 2406 | } |
2408 | 2407 | ||
2409 | if (fbcon_is_inactive(vc, info) || | 2408 | if (mode_switch || fbcon_is_inactive(vc, info) || |
2410 | ops->blank_state != FB_BLANK_UNBLANK) | 2409 | ops->blank_state != FB_BLANK_UNBLANK) |
2411 | fbcon_del_cursor_timer(info); | 2410 | fbcon_del_cursor_timer(info); |
2412 | else | 2411 | else |
diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c index e6aa0eab5bb6..6be72bb218ee 100644 --- a/drivers/video/console/font_10x18.c +++ b/drivers/video/console/font_10x18.c | |||
@@ -5133,14 +5133,14 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = { | |||
5133 | 5133 | ||
5134 | 5134 | ||
5135 | const struct font_desc font_10x18 = { | 5135 | const struct font_desc font_10x18 = { |
5136 | FONT10x18_IDX, | 5136 | .idx = FONT10x18_IDX, |
5137 | "10x18", | 5137 | .name = "10x18", |
5138 | 10, | 5138 | .width = 10, |
5139 | 18, | 5139 | .height = 18, |
5140 | fontdata_10x18, | 5140 | .data = fontdata_10x18, |
5141 | #ifdef __sparc__ | 5141 | #ifdef __sparc__ |
5142 | 5 | 5142 | .pref = 5, |
5143 | #else | 5143 | #else |
5144 | -1 | 5144 | .pref = -1, |
5145 | #endif | 5145 | #endif |
5146 | }; | 5146 | }; |
diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c index 89976cd97494..46e86e67aa6a 100644 --- a/drivers/video/console/font_6x11.c +++ b/drivers/video/console/font_6x11.c | |||
@@ -3342,10 +3342,11 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = { | |||
3342 | 3342 | ||
3343 | 3343 | ||
3344 | const struct font_desc font_vga_6x11 = { | 3344 | const struct font_desc font_vga_6x11 = { |
3345 | VGA6x11_IDX, | 3345 | .idx = VGA6x11_IDX, |
3346 | "ProFont6x11", | 3346 | .name = "ProFont6x11", |
3347 | 6, | 3347 | .width = 6, |
3348 | 11, | 3348 | .height = 11, |
3349 | fontdata_6x11, | 3349 | .data = fontdata_6x11, |
3350 | -2000 /* Try avoiding this font if possible unless on MAC */ | 3350 | /* Try avoiding this font if possible unless on MAC */ |
3351 | .pref = -2000, | ||
3351 | }; | 3352 | }; |
diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c index bbf116647397..3b7dbf9c060b 100644 --- a/drivers/video/console/font_7x14.c +++ b/drivers/video/console/font_7x14.c | |||
@@ -4109,10 +4109,10 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = { | |||
4109 | 4109 | ||
4110 | 4110 | ||
4111 | const struct font_desc font_7x14 = { | 4111 | const struct font_desc font_7x14 = { |
4112 | FONT7x14_IDX, | 4112 | .idx = FONT7x14_IDX, |
4113 | "7x14", | 4113 | .name = "7x14", |
4114 | 7, | 4114 | .width = 7, |
4115 | 14, | 4115 | .height = 14, |
4116 | fontdata_7x14, | 4116 | .data = fontdata_7x14, |
4117 | 0 | 4117 | .pref = 0, |
4118 | }; | 4118 | }; |
diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c index 74fe86f28ff4..00a0c67a5c7d 100644 --- a/drivers/video/console/font_8x16.c +++ b/drivers/video/console/font_8x16.c | |||
@@ -5,6 +5,7 @@ | |||
5 | /**********************************************/ | 5 | /**********************************************/ |
6 | 6 | ||
7 | #include <linux/font.h> | 7 | #include <linux/font.h> |
8 | #include <linux/module.h> | ||
8 | 9 | ||
9 | #define FONTDATAMAX 4096 | 10 | #define FONTDATAMAX 4096 |
10 | 11 | ||
@@ -4622,10 +4623,11 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = { | |||
4622 | 4623 | ||
4623 | 4624 | ||
4624 | const struct font_desc font_vga_8x16 = { | 4625 | const struct font_desc font_vga_8x16 = { |
4625 | VGA8x16_IDX, | 4626 | .idx = VGA8x16_IDX, |
4626 | "VGA8x16", | 4627 | .name = "VGA8x16", |
4627 | 8, | 4628 | .width = 8, |
4628 | 16, | 4629 | .height = 16, |
4629 | fontdata_8x16, | 4630 | .data = fontdata_8x16, |
4630 | 0 | 4631 | .pref = 0, |
4631 | }; | 4632 | }; |
4633 | EXPORT_SYMBOL(font_vga_8x16); | ||
diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c index 26199f8ee908..9f56efe2cee7 100644 --- a/drivers/video/console/font_8x8.c +++ b/drivers/video/console/font_8x8.c | |||
@@ -2574,10 +2574,10 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = { | |||
2574 | 2574 | ||
2575 | 2575 | ||
2576 | const struct font_desc font_vga_8x8 = { | 2576 | const struct font_desc font_vga_8x8 = { |
2577 | VGA8x8_IDX, | 2577 | .idx = VGA8x8_IDX, |
2578 | "VGA8x8", | 2578 | .name = "VGA8x8", |
2579 | 8, | 2579 | .width = 8, |
2580 | 8, | 2580 | .height = 8, |
2581 | fontdata_8x8, | 2581 | .data = fontdata_8x8, |
2582 | 0 | 2582 | .pref = 0, |
2583 | }; | 2583 | }; |
diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c index 40f3d4eeb198..639e31ae1100 100644 --- a/drivers/video/console/font_acorn_8x8.c +++ b/drivers/video/console/font_acorn_8x8.c | |||
@@ -262,14 +262,14 @@ static const unsigned char acorndata_8x8[] = { | |||
262 | }; | 262 | }; |
263 | 263 | ||
264 | const struct font_desc font_acorn_8x8 = { | 264 | const struct font_desc font_acorn_8x8 = { |
265 | ACORN8x8_IDX, | 265 | .idx = ACORN8x8_IDX, |
266 | "Acorn8x8", | 266 | .name = "Acorn8x8", |
267 | 8, | 267 | .width = 8, |
268 | 8, | 268 | .height = 8, |
269 | acorndata_8x8, | 269 | .data = acorndata_8x8, |
270 | #ifdef CONFIG_ARCH_ACORN | 270 | #ifdef CONFIG_ARCH_ACORN |
271 | 20 | 271 | .pref = 20, |
272 | #else | 272 | #else |
273 | 0 | 273 | .pref = 0, |
274 | #endif | 274 | #endif |
275 | }; | 275 | }; |
diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index d818234fdf11..a19a7f33133e 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c | |||
@@ -2148,11 +2148,11 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { | |||
2148 | }; | 2148 | }; |
2149 | 2149 | ||
2150 | const struct font_desc font_mini_4x6 = { | 2150 | const struct font_desc font_mini_4x6 = { |
2151 | MINI4x6_IDX, | 2151 | .idx = MINI4x6_IDX, |
2152 | "MINI4x6", | 2152 | .name = "MINI4x6", |
2153 | 4, | 2153 | .width = 4, |
2154 | 6, | 2154 | .height = 6, |
2155 | fontdata_mini_4x6, | 2155 | .data = fontdata_mini_4x6, |
2156 | 3 | 2156 | .pref = 3, |
2157 | }; | 2157 | }; |
2158 | 2158 | ||
diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c index e646c88f55c7..dc6ad539ca4e 100644 --- a/drivers/video/console/font_pearl_8x8.c +++ b/drivers/video/console/font_pearl_8x8.c | |||
@@ -2578,10 +2578,10 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = { | |||
2578 | }; | 2578 | }; |
2579 | 2579 | ||
2580 | const struct font_desc font_pearl_8x8 = { | 2580 | const struct font_desc font_pearl_8x8 = { |
2581 | PEARL8x8_IDX, | 2581 | .idx = PEARL8x8_IDX, |
2582 | "PEARL8x8", | 2582 | .name = "PEARL8x8", |
2583 | 8, | 2583 | .width = 8, |
2584 | 8, | 2584 | .height = 8, |
2585 | fontdata_pearl8x8, | 2585 | .data = fontdata_pearl8x8, |
2586 | 2 | 2586 | .pref = 2, |
2587 | }; | 2587 | }; |
diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c index ab5eb93407b4..d3643853c33a 100644 --- a/drivers/video/console/font_sun12x22.c +++ b/drivers/video/console/font_sun12x22.c | |||
@@ -6152,14 +6152,14 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = { | |||
6152 | 6152 | ||
6153 | 6153 | ||
6154 | const struct font_desc font_sun_12x22 = { | 6154 | const struct font_desc font_sun_12x22 = { |
6155 | SUN12x22_IDX, | 6155 | .idx = SUN12x22_IDX, |
6156 | "SUN12x22", | 6156 | .name = "SUN12x22", |
6157 | 12, | 6157 | .width = 12, |
6158 | 22, | 6158 | .height = 22, |
6159 | fontdata_sun12x22, | 6159 | .data = fontdata_sun12x22, |
6160 | #ifdef __sparc__ | 6160 | #ifdef __sparc__ |
6161 | 5 | 6161 | .pref = 5, |
6162 | #else | 6162 | #else |
6163 | -1 | 6163 | .pref = -1, |
6164 | #endif | 6164 | #endif |
6165 | }; | 6165 | }; |
diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index 41f910f5529c..5abf290c6eb7 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c | |||
@@ -262,14 +262,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { | |||
262 | }; | 262 | }; |
263 | 263 | ||
264 | const struct font_desc font_sun_8x16 = { | 264 | const struct font_desc font_sun_8x16 = { |
265 | SUN8x16_IDX, | 265 | .idx = SUN8x16_IDX, |
266 | "SUN8x16", | 266 | .name = "SUN8x16", |
267 | 8, | 267 | .width = 8, |
268 | 16, | 268 | .height = 16, |
269 | fontdata_sun8x16, | 269 | .data = fontdata_sun8x16, |
270 | #ifdef __sparc__ | 270 | #ifdef __sparc__ |
271 | 10 | 271 | .pref = 10, |
272 | #else | 272 | #else |
273 | -1 | 273 | .pref = -1, |
274 | #endif | 274 | #endif |
275 | }; | 275 | }; |
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index dda0586ab3f3..f57d7b2758b7 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c | |||
@@ -98,14 +98,19 @@ static inline void newport_init_cmap(void) | |||
98 | } | 98 | } |
99 | } | 99 | } |
100 | 100 | ||
101 | static void newport_show_logo(void) | 101 | static struct linux_logo *newport_show_logo(void) |
102 | { | 102 | { |
103 | #ifdef CONFIG_LOGO_SGI_CLUT224 | 103 | #ifdef CONFIG_LOGO_SGI_CLUT224 |
104 | const struct linux_logo *logo = fb_find_logo(8); | 104 | const struct linux_logo *logo = fb_find_logo(8); |
105 | const unsigned char *clut = logo->clut; | 105 | const unsigned char *clut; |
106 | const unsigned char *data = logo->data; | 106 | const unsigned char *data; |
107 | unsigned long i; | 107 | unsigned long i; |
108 | 108 | ||
109 | if (!logo) | ||
110 | return NULL; | ||
111 | *clut = logo->clut; | ||
112 | *data = logo->data; | ||
113 | |||
109 | for (i = 0; i < logo->clutsize; i++) { | 114 | for (i = 0; i < logo->clutsize; i++) { |
110 | newport_bfwait(npregs); | 115 | newport_bfwait(npregs); |
111 | newport_cmap_setaddr(npregs, i + 0x20); | 116 | newport_cmap_setaddr(npregs, i + 0x20); |
@@ -123,6 +128,8 @@ static void newport_show_logo(void) | |||
123 | 128 | ||
124 | for (i = 0; i < logo->width*logo->height; i++) | 129 | for (i = 0; i < logo->width*logo->height; i++) |
125 | npregs->go.hostrw0 = *data++ << 24; | 130 | npregs->go.hostrw0 = *data++ << 24; |
131 | |||
132 | return logo; | ||
126 | #endif /* CONFIG_LOGO_SGI_CLUT224 */ | 133 | #endif /* CONFIG_LOGO_SGI_CLUT224 */ |
127 | } | 134 | } |
128 | 135 | ||
@@ -465,9 +472,10 @@ static int newport_switch(struct vc_data *vc) | |||
465 | npregs->cset.topscan = 0x3ff; | 472 | npregs->cset.topscan = 0x3ff; |
466 | 473 | ||
467 | if (!logo_drawn) { | 474 | if (!logo_drawn) { |
468 | newport_show_logo(); | 475 | if (newport_show_logo()) { |
469 | logo_drawn = 1; | 476 | logo_drawn = 1; |
470 | logo_active = 1; | 477 | logo_active = 1; |
478 | } | ||
471 | } | 479 | } |
472 | 480 | ||
473 | return 1; | 481 | return 1; |
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index 03cfb7ac5733..25f835bf3d72 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/fb.h> | 15 | #include <linux/fb.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <asm/io.h> | 18 | #include <asm/io.h> |
20 | 19 | ||
21 | #include "fbcon.h" | 20 | #include "fbcon.h" |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d18b73aafa0d..e9afb7ebd566 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -1278,13 +1278,14 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) | |||
1278 | #endif | 1278 | #endif |
1279 | 1279 | ||
1280 | static int vgacon_resize(struct vc_data *c, unsigned int width, | 1280 | static int vgacon_resize(struct vc_data *c, unsigned int width, |
1281 | unsigned int height) | 1281 | unsigned int height, unsigned int user) |
1282 | { | 1282 | { |
1283 | if (width % 2 || width > ORIG_VIDEO_COLS || | 1283 | if (width % 2 || width > ORIG_VIDEO_COLS || |
1284 | height > (ORIG_VIDEO_LINES * vga_default_font_height)/ | 1284 | height > (ORIG_VIDEO_LINES * vga_default_font_height)/ |
1285 | c->vc_font.height) | 1285 | c->vc_font.height) |
1286 | /* let svgatextmode tinker with video timings */ | 1286 | /* let svgatextmode tinker with video timings and |
1287 | return 0; | 1287 | return success */ |
1288 | return (user) ? 0 : -EINVAL; | ||
1288 | 1289 | ||
1289 | if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ | 1290 | if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ |
1290 | vgacon_doresize(c, width, height); | 1291 | vgacon_doresize(c, width, height); |
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 30ede6e8830f..9bb2cbfe4a3d 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -50,7 +50,6 @@ | |||
50 | #include <asm/io.h> | 50 | #include <asm/io.h> |
51 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
52 | #include <asm/system.h> | 52 | #include <asm/system.h> |
53 | #include <asm/uaccess.h> | ||
54 | 53 | ||
55 | #ifdef __arm__ | 54 | #ifdef __arm__ |
56 | #include <asm/mach-types.h> | 55 | #include <asm/mach-types.h> |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 33be46ccb54f..cc2810ef5de5 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -57,7 +57,7 @@ | |||
57 | 57 | ||
58 | #include <asm/types.h> | 58 | #include <asm/types.h> |
59 | #include <asm/io.h> | 59 | #include <asm/io.h> |
60 | #include <asm/uaccess.h> | 60 | #include <linux/uaccess.h> |
61 | 61 | ||
62 | #include <video/epson1355.h> | 62 | #include <video/epson1355.h> |
63 | 63 | ||
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 1a8643f053d8..a0c5d9d90d74 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/fb.h> | 20 | #include <linux/fb.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <asm/uaccess.h> | ||
23 | 22 | ||
24 | /* to support deferred IO */ | 23 | /* to support deferred IO */ |
25 | #include <linux/rmap.h> | 24 | #include <linux/rmap.h> |
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index c5c45203833b..cdafbe14ef1f 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _FB_DRAW_H | 2 | #define _FB_DRAW_H |
3 | 3 | ||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | #include <linux/fb.h> | ||
5 | 6 | ||
6 | /* | 7 | /* |
7 | * Compose two values, using a bitmask as decision value | 8 | * Compose two values, using a bitmask as decision value |
@@ -69,4 +70,97 @@ pixel_to_pat( u32 bpp, u32 pixel) | |||
69 | } | 70 | } |
70 | } | 71 | } |
71 | #endif | 72 | #endif |
73 | |||
74 | #ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE | ||
75 | #if BITS_PER_LONG == 64 | ||
76 | #define REV_PIXELS_MASK1 0x5555555555555555ul | ||
77 | #define REV_PIXELS_MASK2 0x3333333333333333ul | ||
78 | #define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful | ||
79 | #else | ||
80 | #define REV_PIXELS_MASK1 0x55555555ul | ||
81 | #define REV_PIXELS_MASK2 0x33333333ul | ||
82 | #define REV_PIXELS_MASK4 0x0f0f0f0ful | ||
83 | #endif | ||
84 | |||
85 | static inline unsigned long fb_rev_pixels_in_long(unsigned long val, | ||
86 | u32 bswapmask) | ||
87 | { | ||
88 | if (bswapmask & 1) | ||
89 | val = comp(val >> 1, val << 1, REV_PIXELS_MASK1); | ||
90 | if (bswapmask & 2) | ||
91 | val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); | ||
92 | if (bswapmask & 3) | ||
93 | val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); | ||
94 | } | ||
95 | |||
96 | static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) | ||
97 | { | ||
98 | u32 mask; | ||
99 | |||
100 | if (!bswapmask) { | ||
101 | mask = FB_SHIFT_HIGH(~(u32)0, index); | ||
102 | } else { | ||
103 | mask = 0xff << FB_LEFT_POS(8); | ||
104 | mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; | ||
105 | mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); | ||
106 | #if defined(__i386__) || defined(__x86_64__) | ||
107 | /* Shift argument is limited to 0 - 31 on x86 based CPU's */ | ||
108 | if(index + bswapmask < 32) | ||
109 | #endif | ||
110 | mask |= FB_SHIFT_HIGH(~(u32)0, | ||
111 | (index + bswapmask) & ~(bswapmask)); | ||
112 | } | ||
113 | return mask; | ||
114 | } | ||
115 | |||
116 | static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) | ||
117 | { | ||
118 | unsigned long mask; | ||
119 | |||
120 | if (!bswapmask) { | ||
121 | mask = FB_SHIFT_HIGH(~0UL, index); | ||
122 | } else { | ||
123 | mask = 0xff << FB_LEFT_POS(8); | ||
124 | mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; | ||
125 | mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); | ||
126 | #if defined(__i386__) || defined(__x86_64__) | ||
127 | /* Shift argument is limited to 0 - 31 on x86 based CPU's */ | ||
128 | if(index + bswapmask < BITS_PER_LONG) | ||
129 | #endif | ||
130 | mask |= FB_SHIFT_HIGH(~0UL, | ||
131 | (index + bswapmask) & ~(bswapmask)); | ||
132 | } | ||
133 | return mask; | ||
134 | } | ||
135 | |||
136 | |||
137 | static inline u32 fb_compute_bswapmask(struct fb_info *info) | ||
138 | { | ||
139 | u32 bswapmask = 0; | ||
140 | unsigned bpp = info->var.bits_per_pixel; | ||
141 | |||
142 | if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) { | ||
143 | /* | ||
144 | * Reversed order of pixel layout in bytes | ||
145 | * works only for 1, 2 and 4 bpp | ||
146 | */ | ||
147 | bswapmask = 7 - bpp + 1; | ||
148 | } | ||
149 | return bswapmask; | ||
150 | } | ||
151 | |||
152 | #else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ | ||
153 | |||
154 | static inline unsigned long fb_rev_pixels_in_long(unsigned long val, | ||
155 | u32 bswapmask) | ||
156 | { | ||
157 | return val; | ||
158 | } | ||
159 | |||
160 | #define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) | ||
161 | #define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) | ||
162 | #define fb_compute_bswapmask(...) 0 | ||
163 | |||
164 | #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ | ||
165 | |||
72 | #endif /* FB_DRAW_H */ | 166 | #endif /* FB_DRAW_H */ |
diff --git a/drivers/video/fb_sys_fops.c b/drivers/video/fb_sys_fops.c index cf2538d669cd..ff275d7f3eaf 100644 --- a/drivers/video/fb_sys_fops.c +++ b/drivers/video/fb_sys_fops.c | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/fb.h> | 12 | #include <linux/fb.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <asm/uaccess.h> | 14 | #include <linux/uaccess.h> |
15 | 15 | ||
16 | ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, | 16 | ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, |
17 | loff_t *ppos) | 17 | loff_t *ppos) |
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 148108afdd51..91b78e691505 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c | |||
@@ -15,8 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/fb.h> | 16 | #include <linux/fb.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | 18 | #include <linux/uaccess.h> | |
19 | #include <asm/uaccess.h> | ||
20 | 19 | ||
21 | static u16 red2[] __read_mostly = { | 20 | static u16 red2[] __read_mostly = { |
22 | 0x0000, 0xaaaa | 21 | 0x0000, 0xaaaa |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 074027204702..1194f5e060ea 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -1567,8 +1567,6 @@ int fb_new_modelist(struct fb_info *info) | |||
1567 | static char *video_options[FB_MAX] __read_mostly; | 1567 | static char *video_options[FB_MAX] __read_mostly; |
1568 | static int ofonly __read_mostly; | 1568 | static int ofonly __read_mostly; |
1569 | 1569 | ||
1570 | extern const char *global_mode_option; | ||
1571 | |||
1572 | /** | 1570 | /** |
1573 | * fb_get_options - get kernel boot parameters | 1571 | * fb_get_options - get kernel boot parameters |
1574 | * @name: framebuffer name as it would appear in | 1572 | * @name: framebuffer name as it would appear in |
@@ -1636,7 +1634,7 @@ static int __init video_setup(char *options) | |||
1636 | } | 1634 | } |
1637 | 1635 | ||
1638 | if (!global && !strstr(options, "fb:")) { | 1636 | if (!global && !strstr(options, "fb:")) { |
1639 | global_mode_option = options; | 1637 | fb_mode_option = options; |
1640 | global = 1; | 1638 | global = 1; |
1641 | } | 1639 | } |
1642 | 1640 | ||
@@ -1663,7 +1661,6 @@ EXPORT_SYMBOL(register_framebuffer); | |||
1663 | EXPORT_SYMBOL(unregister_framebuffer); | 1661 | EXPORT_SYMBOL(unregister_framebuffer); |
1664 | EXPORT_SYMBOL(num_registered_fb); | 1662 | EXPORT_SYMBOL(num_registered_fb); |
1665 | EXPORT_SYMBOL(registered_fb); | 1663 | EXPORT_SYMBOL(registered_fb); |
1666 | EXPORT_SYMBOL(fb_prepare_logo); | ||
1667 | EXPORT_SYMBOL(fb_show_logo); | 1664 | EXPORT_SYMBOL(fb_show_logo); |
1668 | EXPORT_SYMBOL(fb_set_var); | 1665 | EXPORT_SYMBOL(fb_set_var); |
1669 | EXPORT_SYMBOL(fb_blank); | 1666 | EXPORT_SYMBOL(fb_blank); |
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 438b9411905c..4ba9c0894416 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -591,7 +591,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) | |||
591 | { | 591 | { |
592 | struct fb_videomode *mode, *m; | 592 | struct fb_videomode *mode, *m; |
593 | unsigned char *block; | 593 | unsigned char *block; |
594 | int num = 0, i; | 594 | int num = 0, i, first = 1; |
595 | 595 | ||
596 | mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); | 596 | mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); |
597 | if (mode == NULL) | 597 | if (mode == NULL) |
@@ -608,8 +608,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) | |||
608 | DPRINTK(" Detailed Timings\n"); | 608 | DPRINTK(" Detailed Timings\n"); |
609 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; | 609 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; |
610 | for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { | 610 | for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { |
611 | int first = 1; | ||
612 | |||
613 | if (!(block[0] == 0x00 && block[1] == 0x00)) { | 611 | if (!(block[0] == 0x00 && block[1] == 0x00)) { |
614 | get_detailed_timing(block, &mode[num]); | 612 | get_detailed_timing(block, &mode[num]); |
615 | if (first) { | 613 | if (first) { |
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 5e30b40c8c0f..583185fd7c94 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c | |||
@@ -566,12 +566,7 @@ static int __init lxfb_setup(char *options) | |||
566 | if (!options || !*options) | 566 | if (!options || !*options) |
567 | return 0; | 567 | return 0; |
568 | 568 | ||
569 | while (1) { | 569 | while ((opt = strsep(&options, ",")) != NULL) { |
570 | char *opt = strsep(&options, ","); | ||
571 | |||
572 | if (opt == NULL) | ||
573 | break; | ||
574 | |||
575 | if (!*opt) | 570 | if (!*opt) |
576 | continue; | 571 | continue; |
577 | 572 | ||
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index abfcb50364c8..94e0df8a6f60 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c | |||
@@ -45,7 +45,7 @@ | |||
45 | #include <linux/init.h> | 45 | #include <linux/init.h> |
46 | #include <linux/platform_device.h> | 46 | #include <linux/platform_device.h> |
47 | #include <linux/list.h> | 47 | #include <linux/list.h> |
48 | #include <asm/uaccess.h> | 48 | #include <linux/uaccess.h> |
49 | 49 | ||
50 | /* Apollo controller specific defines */ | 50 | /* Apollo controller specific defines */ |
51 | #define APOLLO_START_NEW_IMG 0xA0 | 51 | #define APOLLO_START_NEW_IMG 0xA0 |
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 94f4511023d8..3ab91bf21576 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <linux/uaccess.h> |
33 | 33 | ||
34 | #if defined(CONFIG_PPC) | 34 | #if defined(CONFIG_PPC) |
35 | #include <linux/nvram.h> | 35 | #include <linux/nvram.h> |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index a12589898597..11609552a387 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -34,7 +34,6 @@ | |||
34 | 34 | ||
35 | #include <asm/hardware.h> | 35 | #include <asm/hardware.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | #include <asm/uaccess.h> | ||
38 | #include <asm/arch/imxfb.h> | 37 | #include <asm/arch/imxfb.h> |
39 | 38 | ||
40 | /* | 39 | /* |
@@ -467,7 +466,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) | |||
467 | info->var.vmode = FB_VMODE_NONINTERLACED; | 466 | info->var.vmode = FB_VMODE_NONINTERLACED; |
468 | 467 | ||
469 | info->fbops = &imxfb_ops; | 468 | info->fbops = &imxfb_ops; |
470 | info->flags = FBINFO_FLAG_DEFAULT; | 469 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; |
471 | 470 | ||
472 | fbi->rgb[RGB_16] = &def_rgb_16; | 471 | fbi->rgb[RGB_16] = &def_rgb_16; |
473 | fbi->rgb[RGB_8] = &def_rgb_8; | 472 | fbi->rgb[RGB_8] = &def_rgb_8; |
@@ -480,6 +479,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) | |||
480 | info->var.yres_virtual = inf->yres; | 479 | info->var.yres_virtual = inf->yres; |
481 | fbi->max_bpp = inf->bpp; | 480 | fbi->max_bpp = inf->bpp; |
482 | info->var.bits_per_pixel = inf->bpp; | 481 | info->var.bits_per_pixel = inf->bpp; |
482 | info->var.nonstd = inf->nonstd; | ||
483 | info->var.pixclock = inf->pixclock; | 483 | info->var.pixclock = inf->pixclock; |
484 | info->var.hsync_len = inf->hsync_len; | 484 | info->var.hsync_len = inf->hsync_len; |
485 | info->var.left_margin = inf->left_margin; | 485 | info->var.left_margin = inf->left_margin; |
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 6148300fadd6..2fe3f7def530 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h | |||
@@ -231,8 +231,8 @@ struct intelfb_hwstate { | |||
231 | struct intelfb_heap_data { | 231 | struct intelfb_heap_data { |
232 | u32 physical; | 232 | u32 physical; |
233 | u8 __iomem *virtual; | 233 | u8 __iomem *virtual; |
234 | u32 offset; // in GATT pages | 234 | u32 offset; /* in GATT pages */ |
235 | u32 size; // in bytes | 235 | u32 size; /* in bytes */ |
236 | }; | 236 | }; |
237 | 237 | ||
238 | #ifdef CONFIG_FB_INTEL_I2C | 238 | #ifdef CONFIG_FB_INTEL_I2C |
@@ -270,9 +270,9 @@ struct intelfb_info { | |||
270 | struct intelfb_hwstate save_state; | 270 | struct intelfb_hwstate save_state; |
271 | 271 | ||
272 | /* agpgart structs */ | 272 | /* agpgart structs */ |
273 | struct agp_memory *gtt_fb_mem; // use all stolen memory or vram | 273 | struct agp_memory *gtt_fb_mem; /* use all stolen memory or vram */ |
274 | struct agp_memory *gtt_ring_mem; // ring buffer | 274 | struct agp_memory *gtt_ring_mem; /* ring buffer */ |
275 | struct agp_memory *gtt_cursor_mem; // hw cursor | 275 | struct agp_memory *gtt_cursor_mem; /* hw cursor */ |
276 | 276 | ||
277 | /* use a gart reserved fb mem */ | 277 | /* use a gart reserved fb mem */ |
278 | u8 fbmem_gart; | 278 | u8 fbmem_gart; |
@@ -346,7 +346,7 @@ struct intelfb_info { | |||
346 | 346 | ||
347 | /* driver registered */ | 347 | /* driver registered */ |
348 | int registered; | 348 | int registered; |
349 | 349 | ||
350 | /* index into plls */ | 350 | /* index into plls */ |
351 | int pll_index; | 351 | int pll_index; |
352 | 352 | ||
@@ -355,7 +355,10 @@ struct intelfb_info { | |||
355 | struct intelfb_output_rec output[MAX_OUTPUTS]; | 355 | struct intelfb_output_rec output[MAX_OUTPUTS]; |
356 | }; | 356 | }; |
357 | 357 | ||
358 | #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM)) | 358 | #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \ |
359 | ((dinfo)->chipset == INTEL_915GM) || \ | ||
360 | ((dinfo)->chipset == INTEL_945G) || \ | ||
361 | ((dinfo)->chipset==INTEL_945GM)) | ||
359 | 362 | ||
360 | #ifndef FBIO_WAITFORVSYNC | 363 | #ifndef FBIO_WAITFORVSYNC |
361 | #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) | 364 | #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) |
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 61e4c8759b23..94c08bb5acf1 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c | |||
@@ -58,7 +58,8 @@ static void intelfb_gpio_setscl(void *data, int state) | |||
58 | struct intelfb_info *dinfo = chan->dinfo; | 58 | struct intelfb_info *dinfo = chan->dinfo; |
59 | u32 val; | 59 | u32 val; |
60 | 60 | ||
61 | OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); | 61 | OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | |
62 | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); | ||
62 | val = INREG(chan->reg); | 63 | val = INREG(chan->reg); |
63 | } | 64 | } |
64 | 65 | ||
@@ -68,7 +69,8 @@ static void intelfb_gpio_setsda(void *data, int state) | |||
68 | struct intelfb_info *dinfo = chan->dinfo; | 69 | struct intelfb_info *dinfo = chan->dinfo; |
69 | u32 val; | 70 | u32 val; |
70 | 71 | ||
71 | OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); | 72 | OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | |
73 | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); | ||
72 | val = INREG(chan->reg); | 74 | val = INREG(chan->reg); |
73 | } | 75 | } |
74 | 76 | ||
@@ -97,26 +99,26 @@ static int intelfb_gpio_getsda(void *data) | |||
97 | } | 99 | } |
98 | 100 | ||
99 | static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, | 101 | static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, |
100 | struct intelfb_i2c_chan *chan, | 102 | struct intelfb_i2c_chan *chan, |
101 | const u32 reg, const char *name) | 103 | const u32 reg, const char *name) |
102 | { | 104 | { |
103 | int rc; | 105 | int rc; |
104 | 106 | ||
105 | chan->dinfo = dinfo; | 107 | chan->dinfo = dinfo; |
106 | chan->reg = reg; | 108 | chan->reg = reg; |
107 | snprintf(chan->adapter.name, sizeof(chan->adapter.name), | 109 | snprintf(chan->adapter.name, sizeof(chan->adapter.name), |
108 | "intelfb %s", name); | 110 | "intelfb %s", name); |
109 | chan->adapter.owner = THIS_MODULE; | 111 | chan->adapter.owner = THIS_MODULE; |
110 | chan->adapter.id = I2C_HW_B_INTELFB; | 112 | chan->adapter.id = I2C_HW_B_INTELFB; |
111 | chan->adapter.algo_data = &chan->algo; | 113 | chan->adapter.algo_data = &chan->algo; |
112 | chan->adapter.dev.parent = &chan->dinfo->pdev->dev; | 114 | chan->adapter.dev.parent = &chan->dinfo->pdev->dev; |
113 | chan->algo.setsda = intelfb_gpio_setsda; | 115 | chan->algo.setsda = intelfb_gpio_setsda; |
114 | chan->algo.setscl = intelfb_gpio_setscl; | 116 | chan->algo.setscl = intelfb_gpio_setscl; |
115 | chan->algo.getsda = intelfb_gpio_getsda; | 117 | chan->algo.getsda = intelfb_gpio_getsda; |
116 | chan->algo.getscl = intelfb_gpio_getscl; | 118 | chan->algo.getscl = intelfb_gpio_getscl; |
117 | chan->algo.udelay = 40; | 119 | chan->algo.udelay = 40; |
118 | chan->algo.timeout = 20; | 120 | chan->algo.timeout = 20; |
119 | chan->algo.data = chan; | 121 | chan->algo.data = chan; |
120 | 122 | ||
121 | i2c_set_adapdata(&chan->adapter, chan); | 123 | i2c_set_adapdata(&chan->adapter, chan); |
122 | 124 | ||
@@ -142,40 +144,44 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) | |||
142 | dinfo->output[i].type = INTELFB_OUTPUT_ANALOG; | 144 | dinfo->output[i].type = INTELFB_OUTPUT_ANALOG; |
143 | 145 | ||
144 | /* setup the DDC bus for analog output */ | 146 | /* setup the DDC bus for analog output */ |
145 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A"); | 147 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, |
148 | "CRTDDC_A"); | ||
146 | i++; | 149 | i++; |
147 | 150 | ||
148 | /* need to add the output busses for each device | 151 | /* need to add the output busses for each device |
149 | - this function is very incomplete | 152 | - this function is very incomplete |
150 | - i915GM has LVDS and TVOUT for example | 153 | - i915GM has LVDS and TVOUT for example |
151 | */ | 154 | */ |
152 | switch(dinfo->chipset) { | 155 | switch(dinfo->chipset) { |
153 | case INTEL_830M: | 156 | case INTEL_830M: |
154 | case INTEL_845G: | 157 | case INTEL_845G: |
155 | case INTEL_855GM: | 158 | case INTEL_855GM: |
156 | case INTEL_865G: | 159 | case INTEL_865G: |
157 | dinfo->output[i].type = INTELFB_OUTPUT_DVO; | 160 | dinfo->output[i].type = INTELFB_OUTPUT_DVO; |
158 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D"); | 161 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, |
159 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E"); | 162 | GPIOD, "DVODDC_D"); |
163 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, | ||
164 | GPIOE, "DVOI2C_E"); | ||
160 | i++; | 165 | i++; |
161 | break; | 166 | break; |
162 | case INTEL_915G: | 167 | case INTEL_915G: |
163 | case INTEL_915GM: | 168 | case INTEL_915GM: |
164 | /* has some LVDS + tv-out */ | 169 | /* has some LVDS + tv-out */ |
165 | case INTEL_945G: | 170 | case INTEL_945G: |
166 | case INTEL_945GM: | 171 | case INTEL_945GM: |
167 | /* SDVO ports have a single control bus - 2 devices */ | 172 | /* SDVO ports have a single control bus - 2 devices */ |
168 | dinfo->output[i].type = INTELFB_OUTPUT_SDVO; | 173 | dinfo->output[i].type = INTELFB_OUTPUT_SDVO; |
169 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E"); | 174 | intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, |
175 | GPIOE, "SDVOCTRL_E"); | ||
170 | /* TODO: initialize the SDVO */ | 176 | /* TODO: initialize the SDVO */ |
171 | // I830SDVOInit(pScrn, i, DVOB); | 177 | /* I830SDVOInit(pScrn, i, DVOB); */ |
172 | i++; | 178 | i++; |
173 | 179 | ||
174 | /* set up SDVOC */ | 180 | /* set up SDVOC */ |
175 | dinfo->output[i].type = INTELFB_OUTPUT_SDVO; | 181 | dinfo->output[i].type = INTELFB_OUTPUT_SDVO; |
176 | dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus; | 182 | dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus; |
177 | /* TODO: initialize the SDVO */ | 183 | /* TODO: initialize the SDVO */ |
178 | // I830SDVOInit(pScrn, i, DVOC); | 184 | /* I830SDVOInit(pScrn, i, DVOC); */ |
179 | i++; | 185 | i++; |
180 | break; | 186 | break; |
181 | } | 187 | } |
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index b75eda84858f..0428f211f192 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c | |||
@@ -99,13 +99,6 @@ | |||
99 | * Add vram option to reserve more memory than stolen by BIOS | 99 | * Add vram option to reserve more memory than stolen by BIOS |
100 | * Fix intelfbhw_pan_display typo | 100 | * Fix intelfbhw_pan_display typo |
101 | * Add __initdata annotations | 101 | * Add __initdata annotations |
102 | * | ||
103 | * TODO: | ||
104 | * | ||
105 | * | ||
106 | * Wish List: | ||
107 | * | ||
108 | * | ||
109 | */ | 102 | */ |
110 | 103 | ||
111 | #include <linux/module.h> | 104 | #include <linux/module.h> |
@@ -222,8 +215,8 @@ static struct pci_driver intelfb_driver = { | |||
222 | /* Module description/parameters */ | 215 | /* Module description/parameters */ |
223 | MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " | 216 | MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " |
224 | "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); | 217 | "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); |
225 | MODULE_DESCRIPTION( | 218 | MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS |
226 | "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); | 219 | " chipsets"); |
227 | MODULE_LICENSE("Dual BSD/GPL"); | 220 | MODULE_LICENSE("Dual BSD/GPL"); |
228 | MODULE_DEVICE_TABLE(pci, intelfb_pci_table); | 221 | MODULE_DEVICE_TABLE(pci, intelfb_pci_table); |
229 | 222 | ||
@@ -271,8 +264,7 @@ MODULE_PARM_DESC(mode, | |||
271 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0) | 264 | #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0) |
272 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) | 265 | #define OPT_STRVAL(opt, name) (opt + strlen(name)) |
273 | 266 | ||
274 | static __inline__ char * | 267 | static __inline__ char * get_opt_string(const char *this_opt, const char *name) |
275 | get_opt_string(const char *this_opt, const char *name) | ||
276 | { | 268 | { |
277 | const char *p; | 269 | const char *p; |
278 | int i; | 270 | int i; |
@@ -290,8 +282,8 @@ get_opt_string(const char *this_opt, const char *name) | |||
290 | return ret; | 282 | return ret; |
291 | } | 283 | } |
292 | 284 | ||
293 | static __inline__ int | 285 | static __inline__ int get_opt_int(const char *this_opt, const char *name, |
294 | get_opt_int(const char *this_opt, const char *name, int *ret) | 286 | int *ret) |
295 | { | 287 | { |
296 | if (!ret) | 288 | if (!ret) |
297 | return 0; | 289 | return 0; |
@@ -303,8 +295,8 @@ get_opt_int(const char *this_opt, const char *name, int *ret) | |||
303 | return 1; | 295 | return 1; |
304 | } | 296 | } |
305 | 297 | ||
306 | static __inline__ int | 298 | static __inline__ int get_opt_bool(const char *this_opt, const char *name, |
307 | get_opt_bool(const char *this_opt, const char *name, int *ret) | 299 | int *ret) |
308 | { | 300 | { |
309 | if (!ret) | 301 | if (!ret) |
310 | return 0; | 302 | return 0; |
@@ -324,8 +316,7 @@ get_opt_bool(const char *this_opt, const char *name, int *ret) | |||
324 | return 1; | 316 | return 1; |
325 | } | 317 | } |
326 | 318 | ||
327 | static int __init | 319 | static int __init intelfb_setup(char *options) |
328 | intelfb_setup(char *options) | ||
329 | { | 320 | { |
330 | char *this_opt; | 321 | char *this_opt; |
331 | 322 | ||
@@ -355,7 +346,7 @@ intelfb_setup(char *options) | |||
355 | continue; | 346 | continue; |
356 | if (get_opt_bool(this_opt, "accel", &accel)) | 347 | if (get_opt_bool(this_opt, "accel", &accel)) |
357 | ; | 348 | ; |
358 | else if (get_opt_int(this_opt, "vram", &vram)) | 349 | else if (get_opt_int(this_opt, "vram", &vram)) |
359 | ; | 350 | ; |
360 | else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) | 351 | else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) |
361 | ; | 352 | ; |
@@ -376,8 +367,7 @@ intelfb_setup(char *options) | |||
376 | 367 | ||
377 | #endif | 368 | #endif |
378 | 369 | ||
379 | static int __init | 370 | static int __init intelfb_init(void) |
380 | intelfb_init(void) | ||
381 | { | 371 | { |
382 | #ifndef MODULE | 372 | #ifndef MODULE |
383 | char *option = NULL; | 373 | char *option = NULL; |
@@ -401,8 +391,7 @@ intelfb_init(void) | |||
401 | return pci_register_driver(&intelfb_driver); | 391 | return pci_register_driver(&intelfb_driver); |
402 | } | 392 | } |
403 | 393 | ||
404 | static void __exit | 394 | static void __exit intelfb_exit(void) |
405 | intelfb_exit(void) | ||
406 | { | 395 | { |
407 | DBG_MSG("intelfb_exit\n"); | 396 | DBG_MSG("intelfb_exit\n"); |
408 | pci_unregister_driver(&intelfb_driver); | 397 | pci_unregister_driver(&intelfb_driver); |
@@ -428,8 +417,8 @@ static inline void __devinit set_mtrr(struct intelfb_info *dinfo) | |||
428 | } | 417 | } |
429 | static inline void unset_mtrr(struct intelfb_info *dinfo) | 418 | static inline void unset_mtrr(struct intelfb_info *dinfo) |
430 | { | 419 | { |
431 | if (dinfo->has_mtrr) | 420 | if (dinfo->has_mtrr) |
432 | mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, | 421 | mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, |
433 | dinfo->aperture.size); | 422 | dinfo->aperture.size); |
434 | } | 423 | } |
435 | #else | 424 | #else |
@@ -442,8 +431,7 @@ static inline void unset_mtrr(struct intelfb_info *dinfo) | |||
442 | * driver init / cleanup * | 431 | * driver init / cleanup * |
443 | ***************************************************************/ | 432 | ***************************************************************/ |
444 | 433 | ||
445 | static void | 434 | static void cleanup(struct intelfb_info *dinfo) |
446 | cleanup(struct intelfb_info *dinfo) | ||
447 | { | 435 | { |
448 | DBG_MSG("cleanup\n"); | 436 | DBG_MSG("cleanup\n"); |
449 | 437 | ||
@@ -499,8 +487,8 @@ cleanup(struct intelfb_info *dinfo) | |||
499 | } while (0) | 487 | } while (0) |
500 | 488 | ||
501 | 489 | ||
502 | static int __devinit | 490 | static int __devinit intelfb_pci_register(struct pci_dev *pdev, |
503 | intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | 491 | const struct pci_device_id *ent) |
504 | { | 492 | { |
505 | struct fb_info *info; | 493 | struct fb_info *info; |
506 | struct intelfb_info *dinfo; | 494 | struct intelfb_info *dinfo; |
@@ -510,8 +498,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
510 | int agp_memtype; | 498 | int agp_memtype; |
511 | const char *s; | 499 | const char *s; |
512 | struct agp_bridge_data *bridge; | 500 | struct agp_bridge_data *bridge; |
513 | int aperture_bar = 0; | 501 | int aperture_bar = 0; |
514 | int mmio_bar = 1; | 502 | int mmio_bar = 1; |
515 | int offset; | 503 | int offset; |
516 | 504 | ||
517 | DBG_MSG("intelfb_pci_register\n"); | 505 | DBG_MSG("intelfb_pci_register\n"); |
@@ -637,9 +625,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
637 | dinfo->ring.size = RINGBUFFER_SIZE; | 625 | dinfo->ring.size = RINGBUFFER_SIZE; |
638 | dinfo->ring_tail_mask = dinfo->ring.size - 1; | 626 | dinfo->ring_tail_mask = dinfo->ring.size - 1; |
639 | } | 627 | } |
640 | if (dinfo->hwcursor) { | 628 | if (dinfo->hwcursor) |
641 | dinfo->cursor.size = HW_CURSOR_SIZE; | 629 | dinfo->cursor.size = HW_CURSOR_SIZE; |
642 | } | ||
643 | 630 | ||
644 | /* Use agpgart to manage the GATT */ | 631 | /* Use agpgart to manage the GATT */ |
645 | if (!(bridge = agp_backend_acquire(pdev))) { | 632 | if (!(bridge = agp_backend_acquire(pdev))) { |
@@ -662,18 +649,15 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
662 | offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; | 649 | offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; |
663 | 650 | ||
664 | /* set the mem offsets - set them after the already used pages */ | 651 | /* set the mem offsets - set them after the already used pages */ |
665 | if (dinfo->accel) { | 652 | if (dinfo->accel) |
666 | dinfo->ring.offset = offset + gtt_info.current_memory; | 653 | dinfo->ring.offset = offset + gtt_info.current_memory; |
667 | } | 654 | if (dinfo->hwcursor) |
668 | if (dinfo->hwcursor) { | ||
669 | dinfo->cursor.offset = offset + | 655 | dinfo->cursor.offset = offset + |
670 | + gtt_info.current_memory + (dinfo->ring.size >> 12); | 656 | + gtt_info.current_memory + (dinfo->ring.size >> 12); |
671 | } | 657 | if (dinfo->fbmem_gart) |
672 | if (dinfo->fbmem_gart) { | ||
673 | dinfo->fb.offset = offset + | 658 | dinfo->fb.offset = offset + |
674 | + gtt_info.current_memory + (dinfo->ring.size >> 12) | 659 | + gtt_info.current_memory + (dinfo->ring.size >> 12) |
675 | + (dinfo->cursor.size >> 12); | 660 | + (dinfo->cursor.size >> 12); |
676 | } | ||
677 | 661 | ||
678 | /* Allocate memories (which aren't stolen) */ | 662 | /* Allocate memories (which aren't stolen) */ |
679 | /* Map the fb and MMIO regions */ | 663 | /* Map the fb and MMIO regions */ |
@@ -689,7 +673,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
689 | 673 | ||
690 | dinfo->mmio_base = | 674 | dinfo->mmio_base = |
691 | (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, | 675 | (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, |
692 | INTEL_REG_SIZE); | 676 | INTEL_REG_SIZE); |
693 | if (!dinfo->mmio_base) { | 677 | if (!dinfo->mmio_base) { |
694 | ERR_MSG("Cannot remap MMIO region.\n"); | 678 | ERR_MSG("Cannot remap MMIO region.\n"); |
695 | cleanup(dinfo); | 679 | cleanup(dinfo); |
@@ -837,10 +821,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
837 | if (bailearly == 3) | 821 | if (bailearly == 3) |
838 | bailout(dinfo); | 822 | bailout(dinfo); |
839 | 823 | ||
840 | if (FIXED_MODE(dinfo)) { | 824 | if (FIXED_MODE(dinfo)) /* remap fb address */ |
841 | /* remap fb address */ | ||
842 | update_dinfo(dinfo, &dinfo->initial_var); | 825 | update_dinfo(dinfo, &dinfo->initial_var); |
843 | } | ||
844 | 826 | ||
845 | if (bailearly == 4) | 827 | if (bailearly == 4) |
846 | bailout(dinfo); | 828 | bailout(dinfo); |
@@ -939,8 +921,7 @@ intelfb_pci_unregister(struct pci_dev *pdev) | |||
939 | * helper functions * | 921 | * helper functions * |
940 | ***************************************************************/ | 922 | ***************************************************************/ |
941 | 923 | ||
942 | int __inline__ | 924 | int __inline__ intelfb_var_to_depth(const struct fb_var_screeninfo *var) |
943 | intelfb_var_to_depth(const struct fb_var_screeninfo *var) | ||
944 | { | 925 | { |
945 | DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", | 926 | DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", |
946 | var->bits_per_pixel, var->green.length); | 927 | var->bits_per_pixel, var->green.length); |
@@ -956,8 +937,7 @@ intelfb_var_to_depth(const struct fb_var_screeninfo *var) | |||
956 | } | 937 | } |
957 | 938 | ||
958 | 939 | ||
959 | static __inline__ int | 940 | static __inline__ int var_to_refresh(const struct fb_var_screeninfo *var) |
960 | var_to_refresh(const struct fb_var_screeninfo *var) | ||
961 | { | 941 | { |
962 | int xtot = var->xres + var->left_margin + var->right_margin + | 942 | int xtot = var->xres + var->left_margin + var->right_margin + |
963 | var->hsync_len; | 943 | var->hsync_len; |
@@ -971,8 +951,7 @@ var_to_refresh(const struct fb_var_screeninfo *var) | |||
971 | * Various intialisation functions * | 951 | * Various intialisation functions * |
972 | ***************************************************************/ | 952 | ***************************************************************/ |
973 | 953 | ||
974 | static void __devinit | 954 | static void __devinit get_initial_mode(struct intelfb_info *dinfo) |
975 | get_initial_mode(struct intelfb_info *dinfo) | ||
976 | { | 955 | { |
977 | struct fb_var_screeninfo *var; | 956 | struct fb_var_screeninfo *var; |
978 | int xtot, ytot; | 957 | int xtot, ytot; |
@@ -1039,8 +1018,7 @@ get_initial_mode(struct intelfb_info *dinfo) | |||
1039 | } | 1018 | } |
1040 | } | 1019 | } |
1041 | 1020 | ||
1042 | static int __devinit | 1021 | static int __devinit intelfb_init_var(struct intelfb_info *dinfo) |
1043 | intelfb_init_var(struct intelfb_info *dinfo) | ||
1044 | { | 1022 | { |
1045 | struct fb_var_screeninfo *var; | 1023 | struct fb_var_screeninfo *var; |
1046 | int msrc = 0; | 1024 | int msrc = 0; |
@@ -1087,10 +1065,9 @@ intelfb_init_var(struct intelfb_info *dinfo) | |||
1087 | 1065 | ||
1088 | } | 1066 | } |
1089 | 1067 | ||
1090 | if (!msrc) { | 1068 | if (!msrc) |
1091 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, | 1069 | msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, |
1092 | NULL, 0, NULL, 0); | 1070 | NULL, 0, NULL, 0); |
1093 | } | ||
1094 | } | 1071 | } |
1095 | 1072 | ||
1096 | if (!msrc) { | 1073 | if (!msrc) { |
@@ -1122,8 +1099,7 @@ intelfb_init_var(struct intelfb_info *dinfo) | |||
1122 | return 0; | 1099 | return 0; |
1123 | } | 1100 | } |
1124 | 1101 | ||
1125 | static int __devinit | 1102 | static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo) |
1126 | intelfb_set_fbinfo(struct intelfb_info *dinfo) | ||
1127 | { | 1103 | { |
1128 | struct fb_info *info = dinfo->info; | 1104 | struct fb_info *info = dinfo->info; |
1129 | 1105 | ||
@@ -1159,8 +1135,8 @@ intelfb_set_fbinfo(struct intelfb_info *dinfo) | |||
1159 | } | 1135 | } |
1160 | 1136 | ||
1161 | /* Update dinfo to match the active video mode. */ | 1137 | /* Update dinfo to match the active video mode. */ |
1162 | static void | 1138 | static void update_dinfo(struct intelfb_info *dinfo, |
1163 | update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) | 1139 | struct fb_var_screeninfo *var) |
1164 | { | 1140 | { |
1165 | DBG_MSG("update_dinfo\n"); | 1141 | DBG_MSG("update_dinfo\n"); |
1166 | 1142 | ||
@@ -1208,36 +1184,32 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) | |||
1208 | * fbdev interface * | 1184 | * fbdev interface * |
1209 | ***************************************************************/ | 1185 | ***************************************************************/ |
1210 | 1186 | ||
1211 | static int | 1187 | static int intelfb_open(struct fb_info *info, int user) |
1212 | intelfb_open(struct fb_info *info, int user) | ||
1213 | { | 1188 | { |
1214 | struct intelfb_info *dinfo = GET_DINFO(info); | 1189 | struct intelfb_info *dinfo = GET_DINFO(info); |
1215 | 1190 | ||
1216 | if (user) { | 1191 | if (user) |
1217 | dinfo->open++; | 1192 | dinfo->open++; |
1218 | } | ||
1219 | 1193 | ||
1220 | return 0; | 1194 | return 0; |
1221 | } | 1195 | } |
1222 | 1196 | ||
1223 | static int | 1197 | static int intelfb_release(struct fb_info *info, int user) |
1224 | intelfb_release(struct fb_info *info, int user) | ||
1225 | { | 1198 | { |
1226 | struct intelfb_info *dinfo = GET_DINFO(info); | 1199 | struct intelfb_info *dinfo = GET_DINFO(info); |
1227 | 1200 | ||
1228 | if (user) { | 1201 | if (user) { |
1229 | dinfo->open--; | 1202 | dinfo->open--; |
1230 | msleep(1); | 1203 | msleep(1); |
1231 | if (!dinfo->open) { | 1204 | if (!dinfo->open) |
1232 | intelfbhw_disable_irq(dinfo); | 1205 | intelfbhw_disable_irq(dinfo); |
1233 | } | ||
1234 | } | 1206 | } |
1235 | 1207 | ||
1236 | return 0; | 1208 | return 0; |
1237 | } | 1209 | } |
1238 | 1210 | ||
1239 | static int | 1211 | static int intelfb_check_var(struct fb_var_screeninfo *var, |
1240 | intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 1212 | struct fb_info *info) |
1241 | { | 1213 | { |
1242 | int change_var = 0; | 1214 | int change_var = 0; |
1243 | struct fb_var_screeninfo v; | 1215 | struct fb_var_screeninfo v; |
@@ -1271,15 +1243,15 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
1271 | } | 1243 | } |
1272 | 1244 | ||
1273 | /* Check for a supported bpp. */ | 1245 | /* Check for a supported bpp. */ |
1274 | if (v.bits_per_pixel <= 8) { | 1246 | if (v.bits_per_pixel <= 8) |
1275 | v.bits_per_pixel = 8; | 1247 | v.bits_per_pixel = 8; |
1276 | } else if (v.bits_per_pixel <= 16) { | 1248 | else if (v.bits_per_pixel <= 16) { |
1277 | if (v.bits_per_pixel == 16) | 1249 | if (v.bits_per_pixel == 16) |
1278 | v.green.length = 6; | 1250 | v.green.length = 6; |
1279 | v.bits_per_pixel = 16; | 1251 | v.bits_per_pixel = 16; |
1280 | } else if (v.bits_per_pixel <= 32) { | 1252 | } else if (v.bits_per_pixel <= 32) |
1281 | v.bits_per_pixel = 32; | 1253 | v.bits_per_pixel = 32; |
1282 | } else | 1254 | else |
1283 | return -EINVAL; | 1255 | return -EINVAL; |
1284 | 1256 | ||
1285 | change_var = ((info->var.xres != var->xres) || | 1257 | change_var = ((info->var.xres != var->xres) || |
@@ -1361,10 +1333,9 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
1361 | return 0; | 1333 | return 0; |
1362 | } | 1334 | } |
1363 | 1335 | ||
1364 | static int | 1336 | static int intelfb_set_par(struct fb_info *info) |
1365 | intelfb_set_par(struct fb_info *info) | ||
1366 | { | 1337 | { |
1367 | struct intelfb_hwstate *hw; | 1338 | struct intelfb_hwstate *hw; |
1368 | struct intelfb_info *dinfo = GET_DINFO(info); | 1339 | struct intelfb_info *dinfo = GET_DINFO(info); |
1369 | 1340 | ||
1370 | if (FIXED_MODE(dinfo)) { | 1341 | if (FIXED_MODE(dinfo)) { |
@@ -1372,9 +1343,9 @@ intelfb_set_par(struct fb_info *info) | |||
1372 | return -EINVAL; | 1343 | return -EINVAL; |
1373 | } | 1344 | } |
1374 | 1345 | ||
1375 | hw = kmalloc(sizeof(*hw), GFP_ATOMIC); | 1346 | hw = kmalloc(sizeof(*hw), GFP_ATOMIC); |
1376 | if (!hw) | 1347 | if (!hw) |
1377 | return -ENOMEM; | 1348 | return -ENOMEM; |
1378 | 1349 | ||
1379 | DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, | 1350 | DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, |
1380 | info->var.yres, info->var.bits_per_pixel); | 1351 | info->var.yres, info->var.bits_per_pixel); |
@@ -1384,15 +1355,15 @@ intelfb_set_par(struct fb_info *info) | |||
1384 | if (ACCEL(dinfo, info)) | 1355 | if (ACCEL(dinfo, info)) |
1385 | intelfbhw_2d_stop(dinfo); | 1356 | intelfbhw_2d_stop(dinfo); |
1386 | 1357 | ||
1387 | memcpy(hw, &dinfo->save_state, sizeof(*hw)); | 1358 | memcpy(hw, &dinfo->save_state, sizeof(*hw)); |
1388 | if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) | 1359 | if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) |
1389 | goto invalid_mode; | 1360 | goto invalid_mode; |
1390 | if (intelfbhw_program_mode(dinfo, hw, 0)) | 1361 | if (intelfbhw_program_mode(dinfo, hw, 0)) |
1391 | goto invalid_mode; | 1362 | goto invalid_mode; |
1392 | 1363 | ||
1393 | #if REGDUMP > 0 | 1364 | #if REGDUMP > 0 |
1394 | intelfbhw_read_hw_state(dinfo, hw, 0); | 1365 | intelfbhw_read_hw_state(dinfo, hw, 0); |
1395 | intelfbhw_print_hw_state(dinfo, hw); | 1366 | intelfbhw_print_hw_state(dinfo, hw); |
1396 | #endif | 1367 | #endif |
1397 | 1368 | ||
1398 | update_dinfo(dinfo, &info->var); | 1369 | update_dinfo(dinfo, &info->var); |
@@ -1408,9 +1379,9 @@ intelfb_set_par(struct fb_info *info) | |||
1408 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | | 1379 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | |
1409 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | | 1380 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | |
1410 | FBINFO_HWACCEL_IMAGEBLIT; | 1381 | FBINFO_HWACCEL_IMAGEBLIT; |
1411 | } else { | 1382 | } else |
1412 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 1383 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
1413 | } | 1384 | |
1414 | kfree(hw); | 1385 | kfree(hw); |
1415 | return 0; | 1386 | return 0; |
1416 | invalid_mode: | 1387 | invalid_mode: |
@@ -1418,9 +1389,9 @@ invalid_mode: | |||
1418 | return -EINVAL; | 1389 | return -EINVAL; |
1419 | } | 1390 | } |
1420 | 1391 | ||
1421 | static int | 1392 | static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
1422 | intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | 1393 | unsigned blue, unsigned transp, |
1423 | unsigned blue, unsigned transp, struct fb_info *info) | 1394 | struct fb_info *info) |
1424 | { | 1395 | { |
1425 | struct intelfb_info *dinfo = GET_DINFO(info); | 1396 | struct intelfb_info *dinfo = GET_DINFO(info); |
1426 | 1397 | ||
@@ -1463,23 +1434,22 @@ intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
1463 | return 0; | 1434 | return 0; |
1464 | } | 1435 | } |
1465 | 1436 | ||
1466 | static int | 1437 | static int intelfb_blank(int blank, struct fb_info *info) |
1467 | intelfb_blank(int blank, struct fb_info *info) | ||
1468 | { | 1438 | { |
1469 | intelfbhw_do_blank(blank, info); | 1439 | intelfbhw_do_blank(blank, info); |
1470 | return 0; | 1440 | return 0; |
1471 | } | 1441 | } |
1472 | 1442 | ||
1473 | static int | 1443 | static int intelfb_pan_display(struct fb_var_screeninfo *var, |
1474 | intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | 1444 | struct fb_info *info) |
1475 | { | 1445 | { |
1476 | intelfbhw_pan_display(var, info); | 1446 | intelfbhw_pan_display(var, info); |
1477 | return 0; | 1447 | return 0; |
1478 | } | 1448 | } |
1479 | 1449 | ||
1480 | /* When/if we have our own ioctls. */ | 1450 | /* When/if we have our own ioctls. */ |
1481 | static int | 1451 | static int intelfb_ioctl(struct fb_info *info, unsigned int cmd, |
1482 | intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 1452 | unsigned long arg) |
1483 | { | 1453 | { |
1484 | int retval = 0; | 1454 | int retval = 0; |
1485 | struct intelfb_info *dinfo = GET_DINFO(info); | 1455 | struct intelfb_info *dinfo = GET_DINFO(info); |
@@ -1499,8 +1469,8 @@ intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | |||
1499 | return retval; | 1469 | return retval; |
1500 | } | 1470 | } |
1501 | 1471 | ||
1502 | static void | 1472 | static void intelfb_fillrect (struct fb_info *info, |
1503 | intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) | 1473 | const struct fb_fillrect *rect) |
1504 | { | 1474 | { |
1505 | struct intelfb_info *dinfo = GET_DINFO(info); | 1475 | struct intelfb_info *dinfo = GET_DINFO(info); |
1506 | u32 rop, color; | 1476 | u32 rop, color; |
@@ -1514,7 +1484,7 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) | |||
1514 | 1484 | ||
1515 | if (rect->rop == ROP_COPY) | 1485 | if (rect->rop == ROP_COPY) |
1516 | rop = PAT_ROP_GXCOPY; | 1486 | rop = PAT_ROP_GXCOPY; |
1517 | else // ROP_XOR | 1487 | else /* ROP_XOR */ |
1518 | rop = PAT_ROP_GXXOR; | 1488 | rop = PAT_ROP_GXXOR; |
1519 | 1489 | ||
1520 | if (dinfo->depth != 8) | 1490 | if (dinfo->depth != 8) |
@@ -1528,8 +1498,8 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) | |||
1528 | rop); | 1498 | rop); |
1529 | } | 1499 | } |
1530 | 1500 | ||
1531 | static void | 1501 | static void intelfb_copyarea(struct fb_info *info, |
1532 | intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) | 1502 | const struct fb_copyarea *region) |
1533 | { | 1503 | { |
1534 | struct intelfb_info *dinfo = GET_DINFO(info); | 1504 | struct intelfb_info *dinfo = GET_DINFO(info); |
1535 | 1505 | ||
@@ -1545,8 +1515,8 @@ intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) | |||
1545 | dinfo->pitch, info->var.bits_per_pixel); | 1515 | dinfo->pitch, info->var.bits_per_pixel); |
1546 | } | 1516 | } |
1547 | 1517 | ||
1548 | static void | 1518 | static void intelfb_imageblit(struct fb_info *info, |
1549 | intelfb_imageblit(struct fb_info *info, const struct fb_image *image) | 1519 | const struct fb_image *image) |
1550 | { | 1520 | { |
1551 | struct intelfb_info *dinfo = GET_DINFO(info); | 1521 | struct intelfb_info *dinfo = GET_DINFO(info); |
1552 | u32 fgcolor, bgcolor; | 1522 | u32 fgcolor, bgcolor; |
@@ -1574,8 +1544,7 @@ intelfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
1574 | return cfb_imageblit(info, image); | 1544 | return cfb_imageblit(info, image); |
1575 | } | 1545 | } |
1576 | 1546 | ||
1577 | static int | 1547 | static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
1578 | intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
1579 | { | 1548 | { |
1580 | struct intelfb_info *dinfo = GET_DINFO(info); | 1549 | struct intelfb_info *dinfo = GET_DINFO(info); |
1581 | u32 physical; | 1550 | u32 physical; |
@@ -1689,8 +1658,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1689 | return 0; | 1658 | return 0; |
1690 | } | 1659 | } |
1691 | 1660 | ||
1692 | static int | 1661 | static int intelfb_sync(struct fb_info *info) |
1693 | intelfb_sync(struct fb_info *info) | ||
1694 | { | 1662 | { |
1695 | struct intelfb_info *dinfo = GET_DINFO(info); | 1663 | struct intelfb_info *dinfo = GET_DINFO(info); |
1696 | 1664 | ||
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 6a47682d8614..2a0e32074f7d 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c | |||
@@ -56,17 +56,16 @@ static struct pll_min_max plls[PLLS_MAX] = { | |||
56 | 6, 16, 3, 16, | 56 | 6, 16, 3, 16, |
57 | 4, 128, 0, 31, | 57 | 4, 128, 0, 31, |
58 | 930000, 1400000, 165000, 48000, | 58 | 930000, 1400000, 165000, 48000, |
59 | 4, 2 }, //I8xx | 59 | 4, 2 }, /* I8xx */ |
60 | 60 | ||
61 | { 75, 120, 10, 20, | 61 | { 75, 120, 10, 20, |
62 | 5, 9, 4, 7, | 62 | 5, 9, 4, 7, |
63 | 5, 80, 1, 8, | 63 | 5, 80, 1, 8, |
64 | 1400000, 2800000, 200000, 96000, | 64 | 1400000, 2800000, 200000, 96000, |
65 | 10, 5 } //I9xx | 65 | 10, 5 } /* I9xx */ |
66 | }; | 66 | }; |
67 | 67 | ||
68 | int | 68 | int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) |
69 | intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) | ||
70 | { | 69 | { |
71 | u32 tmp; | 70 | u32 tmp; |
72 | if (!pdev || !dinfo) | 71 | if (!pdev || !dinfo) |
@@ -149,9 +148,8 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) | |||
149 | } | 148 | } |
150 | } | 149 | } |
151 | 150 | ||
152 | int | 151 | int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, |
153 | intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, | 152 | int *stolen_size) |
154 | int *stolen_size) | ||
155 | { | 153 | { |
156 | struct pci_dev *bridge_dev; | 154 | struct pci_dev *bridge_dev; |
157 | u16 tmp; | 155 | u16 tmp; |
@@ -254,8 +252,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, | |||
254 | } | 252 | } |
255 | } | 253 | } |
256 | 254 | ||
257 | int | 255 | int intelfbhw_check_non_crt(struct intelfb_info *dinfo) |
258 | intelfbhw_check_non_crt(struct intelfb_info *dinfo) | ||
259 | { | 256 | { |
260 | int dvo = 0; | 257 | int dvo = 0; |
261 | 258 | ||
@@ -271,8 +268,7 @@ intelfbhw_check_non_crt(struct intelfb_info *dinfo) | |||
271 | return dvo; | 268 | return dvo; |
272 | } | 269 | } |
273 | 270 | ||
274 | const char * | 271 | const char * intelfbhw_dvo_to_string(int dvo) |
275 | intelfbhw_dvo_to_string(int dvo) | ||
276 | { | 272 | { |
277 | if (dvo & DVOA_PORT) | 273 | if (dvo & DVOA_PORT) |
278 | return "DVO port A"; | 274 | return "DVO port A"; |
@@ -287,9 +283,8 @@ intelfbhw_dvo_to_string(int dvo) | |||
287 | } | 283 | } |
288 | 284 | ||
289 | 285 | ||
290 | int | 286 | int intelfbhw_validate_mode(struct intelfb_info *dinfo, |
291 | intelfbhw_validate_mode(struct intelfb_info *dinfo, | 287 | struct fb_var_screeninfo *var) |
292 | struct fb_var_screeninfo *var) | ||
293 | { | 288 | { |
294 | int bytes_per_pixel; | 289 | int bytes_per_pixel; |
295 | int tmp; | 290 | int tmp; |
@@ -322,17 +317,26 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo, | |||
322 | var->yres, VACTIVE_MASK + 1); | 317 | var->yres, VACTIVE_MASK + 1); |
323 | return 1; | 318 | return 1; |
324 | } | 319 | } |
325 | 320 | if (var->xres < 4) { | |
326 | /* Check for interlaced/doublescan modes. */ | 321 | WRN_MSG("X resolution too small (%d vs 4).\n", var->xres); |
327 | if (var->vmode & FB_VMODE_INTERLACED) { | 322 | return 1; |
328 | WRN_MSG("Mode is interlaced.\n"); | 323 | } |
324 | if (var->yres < 4) { | ||
325 | WRN_MSG("Y resolution too small (%d vs 4).\n", var->yres); | ||
329 | return 1; | 326 | return 1; |
330 | } | 327 | } |
328 | |||
329 | /* Check for doublescan modes. */ | ||
331 | if (var->vmode & FB_VMODE_DOUBLE) { | 330 | if (var->vmode & FB_VMODE_DOUBLE) { |
332 | WRN_MSG("Mode is double-scan.\n"); | 331 | WRN_MSG("Mode is double-scan.\n"); |
333 | return 1; | 332 | return 1; |
334 | } | 333 | } |
335 | 334 | ||
335 | if ((var->vmode & FB_VMODE_INTERLACED) && (var->yres & 1)) { | ||
336 | WRN_MSG("Odd number of lines in interlaced mode\n"); | ||
337 | return 1; | ||
338 | } | ||
339 | |||
336 | /* Check if clock is OK. */ | 340 | /* Check if clock is OK. */ |
337 | tmp = 1000000000 / var->pixclock; | 341 | tmp = 1000000000 / var->pixclock; |
338 | if (tmp < MIN_CLOCK) { | 342 | if (tmp < MIN_CLOCK) { |
@@ -349,8 +353,7 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo, | |||
349 | return 0; | 353 | return 0; |
350 | } | 354 | } |
351 | 355 | ||
352 | int | 356 | int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) |
353 | intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | ||
354 | { | 357 | { |
355 | struct intelfb_info *dinfo = GET_DINFO(info); | 358 | struct intelfb_info *dinfo = GET_DINFO(info); |
356 | u32 offset, xoffset, yoffset; | 359 | u32 offset, xoffset, yoffset; |
@@ -372,9 +375,10 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |||
372 | offset += dinfo->fb.offset << 12; | 375 | offset += dinfo->fb.offset << 12; |
373 | 376 | ||
374 | dinfo->vsync.pan_offset = offset; | 377 | dinfo->vsync.pan_offset = offset; |
375 | if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) { | 378 | if ((var->activate & FB_ACTIVATE_VBL) && |
379 | !intelfbhw_enable_irq(dinfo)) | ||
376 | dinfo->vsync.pan_display = 1; | 380 | dinfo->vsync.pan_display = 1; |
377 | } else { | 381 | else { |
378 | dinfo->vsync.pan_display = 0; | 382 | dinfo->vsync.pan_display = 0; |
379 | OUTREG(DSPABASE, offset); | 383 | OUTREG(DSPABASE, offset); |
380 | } | 384 | } |
@@ -383,8 +387,7 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |||
383 | } | 387 | } |
384 | 388 | ||
385 | /* Blank the screen. */ | 389 | /* Blank the screen. */ |
386 | void | 390 | void intelfbhw_do_blank(int blank, struct fb_info *info) |
387 | intelfbhw_do_blank(int blank, struct fb_info *info) | ||
388 | { | 391 | { |
389 | struct intelfb_info *dinfo = GET_DINFO(info); | 392 | struct intelfb_info *dinfo = GET_DINFO(info); |
390 | u32 tmp; | 393 | u32 tmp; |
@@ -409,11 +412,10 @@ intelfbhw_do_blank(int blank, struct fb_info *info) | |||
409 | DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); | 412 | DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); |
410 | #endif | 413 | #endif |
411 | if (dinfo->cursor_on) { | 414 | if (dinfo->cursor_on) { |
412 | if (blank) { | 415 | if (blank) |
413 | intelfbhw_cursor_hide(dinfo); | 416 | intelfbhw_cursor_hide(dinfo); |
414 | } else { | 417 | else |
415 | intelfbhw_cursor_show(dinfo); | 418 | intelfbhw_cursor_show(dinfo); |
416 | } | ||
417 | dinfo->cursor_on = 1; | 419 | dinfo->cursor_on = 1; |
418 | } | 420 | } |
419 | dinfo->cursor_blanked = blank; | 421 | dinfo->cursor_blanked = blank; |
@@ -441,19 +443,18 @@ intelfbhw_do_blank(int blank, struct fb_info *info) | |||
441 | } | 443 | } |
442 | 444 | ||
443 | 445 | ||
444 | void | 446 | void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, |
445 | intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, | 447 | unsigned red, unsigned green, unsigned blue, |
446 | unsigned red, unsigned green, unsigned blue, | 448 | unsigned transp) |
447 | unsigned transp) | ||
448 | { | 449 | { |
450 | u32 palette_reg = (dinfo->pipe == PIPE_A) ? | ||
451 | PALETTE_A : PALETTE_B; | ||
452 | |||
449 | #if VERBOSE > 0 | 453 | #if VERBOSE > 0 |
450 | DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", | 454 | DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", |
451 | regno, red, green, blue); | 455 | regno, red, green, blue); |
452 | #endif | 456 | #endif |
453 | 457 | ||
454 | u32 palette_reg = (dinfo->pipe == PIPE_A) ? | ||
455 | PALETTE_A : PALETTE_B; | ||
456 | |||
457 | OUTREG(palette_reg + (regno << 2), | 458 | OUTREG(palette_reg + (regno << 2), |
458 | (red << PALETTE_8_RED_SHIFT) | | 459 | (red << PALETTE_8_RED_SHIFT) | |
459 | (green << PALETTE_8_GREEN_SHIFT) | | 460 | (green << PALETTE_8_GREEN_SHIFT) | |
@@ -461,9 +462,8 @@ intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, | |||
461 | } | 462 | } |
462 | 463 | ||
463 | 464 | ||
464 | int | 465 | int intelfbhw_read_hw_state(struct intelfb_info *dinfo, |
465 | intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | 466 | struct intelfb_hwstate *hw, int flag) |
466 | int flag) | ||
467 | { | 467 | { |
468 | int i; | 468 | int i; |
469 | 469 | ||
@@ -610,7 +610,8 @@ static int calc_vclock3(int index, int m, int n, int p) | |||
610 | return plls[index].ref_clk * m / n / p; | 610 | return plls[index].ref_clk * m / n / p; |
611 | } | 611 | } |
612 | 612 | ||
613 | static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds) | 613 | static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, |
614 | int lvds) | ||
614 | { | 615 | { |
615 | struct pll_min_max *pll = &plls[index]; | 616 | struct pll_min_max *pll = &plls[index]; |
616 | u32 m, vco, p; | 617 | u32 m, vco, p; |
@@ -619,17 +620,16 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd | |||
619 | n += 2; | 620 | n += 2; |
620 | vco = pll->ref_clk * m / n; | 621 | vco = pll->ref_clk * m / n; |
621 | 622 | ||
622 | if (index == PLLS_I8xx) { | 623 | if (index == PLLS_I8xx) |
623 | p = ((p1 + 2) * (1 << (p2 + 1))); | 624 | p = ((p1 + 2) * (1 << (p2 + 1))); |
624 | } else { | 625 | else |
625 | p = ((p1) * (p2 ? 5 : 10)); | 626 | p = ((p1) * (p2 ? 5 : 10)); |
626 | } | ||
627 | return vco / p; | 627 | return vco / p; |
628 | } | 628 | } |
629 | 629 | ||
630 | #if REGDUMP | 630 | #if REGDUMP |
631 | static void | 631 | static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, |
632 | intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) | 632 | int *o_p1, int *o_p2) |
633 | { | 633 | { |
634 | int p1, p2; | 634 | int p1, p2; |
635 | 635 | ||
@@ -638,7 +638,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) | |||
638 | p1 = 1; | 638 | p1 = 1; |
639 | else | 639 | else |
640 | p1 = (dpll >> DPLL_P1_SHIFT) & 0xff; | 640 | p1 = (dpll >> DPLL_P1_SHIFT) & 0xff; |
641 | 641 | ||
642 | p1 = ffs(p1); | 642 | p1 = ffs(p1); |
643 | 643 | ||
644 | p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK; | 644 | p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK; |
@@ -656,8 +656,8 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) | |||
656 | #endif | 656 | #endif |
657 | 657 | ||
658 | 658 | ||
659 | void | 659 | void intelfbhw_print_hw_state(struct intelfb_info *dinfo, |
660 | intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | 660 | struct intelfb_hwstate *hw) |
661 | { | 661 | { |
662 | #if REGDUMP | 662 | #if REGDUMP |
663 | int i, m1, m2, n, p1, p2; | 663 | int i, m1, m2, n, p1, p2; |
@@ -670,7 +670,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | |||
670 | printk("hw state dump start\n"); | 670 | printk("hw state dump start\n"); |
671 | printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); | 671 | printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); |
672 | printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); | 672 | printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); |
673 | printk(" VGAPD: 0x%08x\n", hw->vga_pd); | 673 | printk(" VGAPD: 0x%08x\n", hw->vga_pd); |
674 | n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 674 | n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
675 | m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 675 | m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
676 | m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 676 | m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
@@ -689,7 +689,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | |||
689 | intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2); | 689 | intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2); |
690 | printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 690 | printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
691 | m1, m2, n, p1, p2); | 691 | m1, m2, n, p1, p2); |
692 | printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); | 692 | printk(" VGA1: clock is %d\n", |
693 | calc_vclock(index, m1, m2, n, p1, p2, 0)); | ||
693 | 694 | ||
694 | printk(" DPLL_A: 0x%08x\n", hw->dpll_a); | 695 | printk(" DPLL_A: 0x%08x\n", hw->dpll_a); |
695 | printk(" DPLL_B: 0x%08x\n", hw->dpll_b); | 696 | printk(" DPLL_B: 0x%08x\n", hw->dpll_b); |
@@ -706,7 +707,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | |||
706 | 707 | ||
707 | printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 708 | printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
708 | m1, m2, n, p1, p2); | 709 | m1, m2, n, p1, p2); |
709 | printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); | 710 | printk(" PLLA0: clock is %d\n", |
711 | calc_vclock(index, m1, m2, n, p1, p2, 0)); | ||
710 | 712 | ||
711 | n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 713 | n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
712 | m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; | 714 | m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; |
@@ -716,7 +718,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | |||
716 | 718 | ||
717 | printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", | 719 | printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", |
718 | m1, m2, n, p1, p2); | 720 | m1, m2, n, p1, p2); |
719 | printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); | 721 | printk(" PLLA1: clock is %d\n", |
722 | calc_vclock(index, m1, m2, n, p1, p2, 0)); | ||
720 | 723 | ||
721 | #if 0 | 724 | #if 0 |
722 | printk(" PALETTE_A:\n"); | 725 | printk(" PALETTE_A:\n"); |
@@ -821,8 +824,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) | |||
821 | 824 | ||
822 | 825 | ||
823 | /* Split the M parameter into M1 and M2. */ | 826 | /* Split the M parameter into M1 and M2. */ |
824 | static int | 827 | static int splitm(int index, unsigned int m, unsigned int *retm1, |
825 | splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2) | 828 | unsigned int *retm2) |
826 | { | 829 | { |
827 | int m1, m2; | 830 | int m1, m2; |
828 | int testm; | 831 | int testm; |
@@ -843,8 +846,8 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2) | |||
843 | } | 846 | } |
844 | 847 | ||
845 | /* Split the P parameter into P1 and P2. */ | 848 | /* Split the P parameter into P1 and P2. */ |
846 | static int | 849 | static int splitp(int index, unsigned int p, unsigned int *retp1, |
847 | splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2) | 850 | unsigned int *retp2) |
848 | { | 851 | { |
849 | int p1, p2; | 852 | int p1, p2; |
850 | struct pll_min_max *pll = &plls[index]; | 853 | struct pll_min_max *pll = &plls[index]; |
@@ -878,9 +881,8 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2) | |||
878 | } | 881 | } |
879 | } | 882 | } |
880 | 883 | ||
881 | static int | 884 | static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, |
882 | calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, | 885 | u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock) |
883 | u32 *retp2, u32 *retclock) | ||
884 | { | 886 | { |
885 | u32 m1, m2, n, p1, p2, n1, testm; | 887 | u32 m1, m2, n, p1, p2, n1, testm; |
886 | u32 f_vco, p, p_best = 0, m, f_out = 0; | 888 | u32 f_vco, p, p_best = 0, m, f_out = 0; |
@@ -975,8 +977,8 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re | |||
975 | return 0; | 977 | return 0; |
976 | } | 978 | } |
977 | 979 | ||
978 | static __inline__ int | 980 | static __inline__ int check_overflow(u32 value, u32 limit, |
979 | check_overflow(u32 value, u32 limit, const char *description) | 981 | const char *description) |
980 | { | 982 | { |
981 | if (value > limit) { | 983 | if (value > limit) { |
982 | WRN_MSG("%s value %d exceeds limit %d\n", | 984 | WRN_MSG("%s value %d exceeds limit %d\n", |
@@ -987,9 +989,9 @@ check_overflow(u32 value, u32 limit, const char *description) | |||
987 | } | 989 | } |
988 | 990 | ||
989 | /* It is assumed that hw is filled in with the initial state information. */ | 991 | /* It is assumed that hw is filled in with the initial state information. */ |
990 | int | 992 | int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, |
991 | intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | 993 | struct intelfb_hwstate *hw, |
992 | struct fb_var_screeninfo *var) | 994 | struct fb_var_screeninfo *var) |
993 | { | 995 | { |
994 | int pipe = PIPE_A; | 996 | int pipe = PIPE_A; |
995 | u32 *dpll, *fp0, *fp1; | 997 | u32 *dpll, *fp0, *fp1; |
@@ -1093,9 +1095,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | |||
1093 | if (IS_I9XX(dinfo)) { | 1095 | if (IS_I9XX(dinfo)) { |
1094 | *dpll |= (p2 << DPLL_I9XX_P2_SHIFT); | 1096 | *dpll |= (p2 << DPLL_I9XX_P2_SHIFT); |
1095 | *dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT; | 1097 | *dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT; |
1096 | } else { | 1098 | } else |
1097 | *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); | 1099 | *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); |
1098 | } | ||
1099 | 1100 | ||
1100 | *fp0 = (n << FP_N_DIVISOR_SHIFT) | | 1101 | *fp0 = (n << FP_N_DIVISOR_SHIFT) | |
1101 | (m1 << FP_M1_DIVISOR_SHIFT) | | 1102 | (m1 << FP_M1_DIVISOR_SHIFT) | |
@@ -1139,6 +1140,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | |||
1139 | hblank_end); | 1140 | hblank_end); |
1140 | 1141 | ||
1141 | vactive = var->yres; | 1142 | vactive = var->yres; |
1143 | if (var->vmode & FB_VMODE_INTERLACED) | ||
1144 | vactive--; /* the chip adds 2 halflines automatically */ | ||
1142 | vsync_start = vactive + var->lower_margin; | 1145 | vsync_start = vactive + var->lower_margin; |
1143 | vsync_end = vsync_start + var->vsync_len; | 1146 | vsync_end = vsync_start + var->vsync_len; |
1144 | vtotal = vsync_end + var->upper_margin; | 1147 | vtotal = vsync_end + var->upper_margin; |
@@ -1220,19 +1223,24 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, | |||
1220 | 1223 | ||
1221 | /* Set the palette to 8-bit mode. */ | 1224 | /* Set the palette to 8-bit mode. */ |
1222 | *pipe_conf &= ~PIPECONF_GAMMA; | 1225 | *pipe_conf &= ~PIPECONF_GAMMA; |
1226 | |||
1227 | if (var->vmode & FB_VMODE_INTERLACED) | ||
1228 | *pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; | ||
1229 | else | ||
1230 | *pipe_conf &= ~PIPECONF_INTERLACE_MASK; | ||
1231 | |||
1223 | return 0; | 1232 | return 0; |
1224 | } | 1233 | } |
1225 | 1234 | ||
1226 | /* Program a (non-VGA) video mode. */ | 1235 | /* Program a (non-VGA) video mode. */ |
1227 | int | 1236 | int intelfbhw_program_mode(struct intelfb_info *dinfo, |
1228 | intelfbhw_program_mode(struct intelfb_info *dinfo, | 1237 | const struct intelfb_hwstate *hw, int blank) |
1229 | const struct intelfb_hwstate *hw, int blank) | ||
1230 | { | 1238 | { |
1231 | int pipe = PIPE_A; | 1239 | int pipe = PIPE_A; |
1232 | u32 tmp; | 1240 | u32 tmp; |
1233 | const u32 *dpll, *fp0, *fp1, *pipe_conf; | 1241 | const u32 *dpll, *fp0, *fp1, *pipe_conf; |
1234 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; | 1242 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; |
1235 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; | 1243 | u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg; |
1236 | u32 hsync_reg, htotal_reg, hblank_reg; | 1244 | u32 hsync_reg, htotal_reg, hblank_reg; |
1237 | u32 vsync_reg, vtotal_reg, vblank_reg; | 1245 | u32 vsync_reg, vtotal_reg, vblank_reg; |
1238 | u32 src_size_reg; | 1246 | u32 src_size_reg; |
@@ -1273,6 +1281,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1273 | fp0_reg = FPB0; | 1281 | fp0_reg = FPB0; |
1274 | fp1_reg = FPB1; | 1282 | fp1_reg = FPB1; |
1275 | pipe_conf_reg = PIPEBCONF; | 1283 | pipe_conf_reg = PIPEBCONF; |
1284 | pipe_stat_reg = PIPEBSTAT; | ||
1276 | hsync_reg = HSYNC_B; | 1285 | hsync_reg = HSYNC_B; |
1277 | htotal_reg = HTOTAL_B; | 1286 | htotal_reg = HTOTAL_B; |
1278 | hblank_reg = HBLANK_B; | 1287 | hblank_reg = HBLANK_B; |
@@ -1296,6 +1305,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1296 | fp0_reg = FPA0; | 1305 | fp0_reg = FPA0; |
1297 | fp1_reg = FPA1; | 1306 | fp1_reg = FPA1; |
1298 | pipe_conf_reg = PIPEACONF; | 1307 | pipe_conf_reg = PIPEACONF; |
1308 | pipe_stat_reg = PIPEASTAT; | ||
1299 | hsync_reg = HSYNC_A; | 1309 | hsync_reg = HSYNC_A; |
1300 | htotal_reg = HTOTAL_A; | 1310 | htotal_reg = HTOTAL_A; |
1301 | hblank_reg = HBLANK_A; | 1311 | hblank_reg = HBLANK_A; |
@@ -1312,8 +1322,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1312 | 1322 | ||
1313 | count = 0; | 1323 | count = 0; |
1314 | do { | 1324 | do { |
1315 | tmp_val[count%3] = INREG(0x70000); | 1325 | tmp_val[count % 3] = INREG(PIPEA_DSL); |
1316 | if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2])) | 1326 | if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2])) |
1317 | break; | 1327 | break; |
1318 | count++; | 1328 | count++; |
1319 | udelay(1); | 1329 | udelay(1); |
@@ -1322,7 +1332,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1322 | tmp &= ~PIPECONF_ENABLE; | 1332 | tmp &= ~PIPECONF_ENABLE; |
1323 | OUTREG(pipe_conf_reg, tmp); | 1333 | OUTREG(pipe_conf_reg, tmp); |
1324 | } | 1334 | } |
1325 | } while(count < 2000); | 1335 | } while (count < 2000); |
1326 | 1336 | ||
1327 | OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE); | 1337 | OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE); |
1328 | 1338 | ||
@@ -1382,6 +1392,17 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1382 | OUTREG(vtotal_reg, *vt); | 1392 | OUTREG(vtotal_reg, *vt); |
1383 | OUTREG(src_size_reg, *ss); | 1393 | OUTREG(src_size_reg, *ss); |
1384 | 1394 | ||
1395 | switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED | | ||
1396 | FB_VMODE_ODD_FLD_FIRST)) { | ||
1397 | case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST: | ||
1398 | OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN); | ||
1399 | break; | ||
1400 | case FB_VMODE_INTERLACED: /* even lines first */ | ||
1401 | OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN); | ||
1402 | break; | ||
1403 | default: /* non-interlaced */ | ||
1404 | OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */ | ||
1405 | } | ||
1385 | /* Enable pipe */ | 1406 | /* Enable pipe */ |
1386 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); | 1407 | OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); |
1387 | 1408 | ||
@@ -1446,8 +1467,7 @@ static u32 get_ring_space(struct intelfb_info *dinfo) | |||
1446 | return ring_space; | 1467 | return ring_space; |
1447 | } | 1468 | } |
1448 | 1469 | ||
1449 | static int | 1470 | static int wait_ring(struct intelfb_info *dinfo, int n) |
1450 | wait_ring(struct intelfb_info *dinfo, int n) | ||
1451 | { | 1471 | { |
1452 | int i = 0; | 1472 | int i = 0; |
1453 | unsigned long end; | 1473 | unsigned long end; |
@@ -1489,16 +1509,15 @@ wait_ring(struct intelfb_info *dinfo, int n) | |||
1489 | return i; | 1509 | return i; |
1490 | } | 1510 | } |
1491 | 1511 | ||
1492 | static void | 1512 | static void do_flush(struct intelfb_info *dinfo) |
1493 | do_flush(struct intelfb_info *dinfo) { | 1513 | { |
1494 | START_RING(2); | 1514 | START_RING(2); |
1495 | OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); | 1515 | OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); |
1496 | OUT_RING(MI_NOOP); | 1516 | OUT_RING(MI_NOOP); |
1497 | ADVANCE_RING(); | 1517 | ADVANCE_RING(); |
1498 | } | 1518 | } |
1499 | 1519 | ||
1500 | void | 1520 | void intelfbhw_do_sync(struct intelfb_info *dinfo) |
1501 | intelfbhw_do_sync(struct intelfb_info *dinfo) | ||
1502 | { | 1521 | { |
1503 | #if VERBOSE > 0 | 1522 | #if VERBOSE > 0 |
1504 | DBG_MSG("intelfbhw_do_sync\n"); | 1523 | DBG_MSG("intelfbhw_do_sync\n"); |
@@ -1517,8 +1536,7 @@ intelfbhw_do_sync(struct intelfb_info *dinfo) | |||
1517 | dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; | 1536 | dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; |
1518 | } | 1537 | } |
1519 | 1538 | ||
1520 | static void | 1539 | static void refresh_ring(struct intelfb_info *dinfo) |
1521 | refresh_ring(struct intelfb_info *dinfo) | ||
1522 | { | 1540 | { |
1523 | #if VERBOSE > 0 | 1541 | #if VERBOSE > 0 |
1524 | DBG_MSG("refresh_ring\n"); | 1542 | DBG_MSG("refresh_ring\n"); |
@@ -1529,8 +1547,7 @@ refresh_ring(struct intelfb_info *dinfo) | |||
1529 | dinfo->ring_space = get_ring_space(dinfo); | 1547 | dinfo->ring_space = get_ring_space(dinfo); |
1530 | } | 1548 | } |
1531 | 1549 | ||
1532 | static void | 1550 | static void reset_state(struct intelfb_info *dinfo) |
1533 | reset_state(struct intelfb_info *dinfo) | ||
1534 | { | 1551 | { |
1535 | int i; | 1552 | int i; |
1536 | u32 tmp; | 1553 | u32 tmp; |
@@ -1560,12 +1577,11 @@ reset_state(struct intelfb_info *dinfo) | |||
1560 | } | 1577 | } |
1561 | 1578 | ||
1562 | /* Stop the 2D engine, and turn off the ring buffer. */ | 1579 | /* Stop the 2D engine, and turn off the ring buffer. */ |
1563 | void | 1580 | void intelfbhw_2d_stop(struct intelfb_info *dinfo) |
1564 | intelfbhw_2d_stop(struct intelfb_info *dinfo) | ||
1565 | { | 1581 | { |
1566 | #if VERBOSE > 0 | 1582 | #if VERBOSE > 0 |
1567 | DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, | 1583 | DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", |
1568 | dinfo->ring_active); | 1584 | dinfo->accel, dinfo->ring_active); |
1569 | #endif | 1585 | #endif |
1570 | 1586 | ||
1571 | if (!dinfo->accel) | 1587 | if (!dinfo->accel) |
@@ -1580,8 +1596,7 @@ intelfbhw_2d_stop(struct intelfb_info *dinfo) | |||
1580 | * It is assumed that the graphics engine has been stopped by previously | 1596 | * It is assumed that the graphics engine has been stopped by previously |
1581 | * calling intelfb_2d_stop(). | 1597 | * calling intelfb_2d_stop(). |
1582 | */ | 1598 | */ |
1583 | void | 1599 | void intelfbhw_2d_start(struct intelfb_info *dinfo) |
1584 | intelfbhw_2d_start(struct intelfb_info *dinfo) | ||
1585 | { | 1600 | { |
1586 | #if VERBOSE > 0 | 1601 | #if VERBOSE > 0 |
1587 | DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", | 1602 | DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", |
@@ -1605,9 +1620,8 @@ intelfbhw_2d_start(struct intelfb_info *dinfo) | |||
1605 | } | 1620 | } |
1606 | 1621 | ||
1607 | /* 2D fillrect (solid fill or invert) */ | 1622 | /* 2D fillrect (solid fill or invert) */ |
1608 | void | 1623 | void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, |
1609 | intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, | 1624 | u32 h, u32 color, u32 pitch, u32 bpp, u32 rop) |
1610 | u32 color, u32 pitch, u32 bpp, u32 rop) | ||
1611 | { | 1625 | { |
1612 | u32 br00, br09, br13, br14, br16; | 1626 | u32 br00, br09, br13, br14, br16; |
1613 | 1627 | ||
@@ -1696,9 +1710,9 @@ intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, | |||
1696 | ADVANCE_RING(); | 1710 | ADVANCE_RING(); |
1697 | } | 1711 | } |
1698 | 1712 | ||
1699 | int | 1713 | int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, |
1700 | intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, | 1714 | u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, |
1701 | u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp) | 1715 | u32 bpp) |
1702 | { | 1716 | { |
1703 | int nbytes, ndwords, pad, tmp; | 1717 | int nbytes, ndwords, pad, tmp; |
1704 | u32 br00, br09, br13, br18, br19, br22, br23; | 1718 | u32 br00, br09, br13, br18, br19, br22, br23; |
@@ -1785,8 +1799,7 @@ intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, | |||
1785 | } | 1799 | } |
1786 | 1800 | ||
1787 | /* HW cursor functions. */ | 1801 | /* HW cursor functions. */ |
1788 | void | 1802 | void intelfbhw_cursor_init(struct intelfb_info *dinfo) |
1789 | intelfbhw_cursor_init(struct intelfb_info *dinfo) | ||
1790 | { | 1803 | { |
1791 | u32 tmp; | 1804 | u32 tmp; |
1792 | 1805 | ||
@@ -1817,8 +1830,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo) | |||
1817 | } | 1830 | } |
1818 | } | 1831 | } |
1819 | 1832 | ||
1820 | void | 1833 | void intelfbhw_cursor_hide(struct intelfb_info *dinfo) |
1821 | intelfbhw_cursor_hide(struct intelfb_info *dinfo) | ||
1822 | { | 1834 | { |
1823 | u32 tmp; | 1835 | u32 tmp; |
1824 | 1836 | ||
@@ -1843,8 +1855,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo) | |||
1843 | } | 1855 | } |
1844 | } | 1856 | } |
1845 | 1857 | ||
1846 | void | 1858 | void intelfbhw_cursor_show(struct intelfb_info *dinfo) |
1847 | intelfbhw_cursor_show(struct intelfb_info *dinfo) | ||
1848 | { | 1859 | { |
1849 | u32 tmp; | 1860 | u32 tmp; |
1850 | 1861 | ||
@@ -1873,8 +1884,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo) | |||
1873 | } | 1884 | } |
1874 | } | 1885 | } |
1875 | 1886 | ||
1876 | void | 1887 | void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) |
1877 | intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) | ||
1878 | { | 1888 | { |
1879 | u32 tmp; | 1889 | u32 tmp; |
1880 | 1890 | ||
@@ -1892,13 +1902,11 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) | |||
1892 | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | 1902 | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); |
1893 | OUTREG(CURSOR_A_POSITION, tmp); | 1903 | OUTREG(CURSOR_A_POSITION, tmp); |
1894 | 1904 | ||
1895 | if (IS_I9XX(dinfo)) { | 1905 | if (IS_I9XX(dinfo)) |
1896 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); | 1906 | OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); |
1897 | } | ||
1898 | } | 1907 | } |
1899 | 1908 | ||
1900 | void | 1909 | void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) |
1901 | intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) | ||
1902 | { | 1910 | { |
1903 | #if VERBOSE > 0 | 1911 | #if VERBOSE > 0 |
1904 | DBG_MSG("intelfbhw_cursor_setcolor\n"); | 1912 | DBG_MSG("intelfbhw_cursor_setcolor\n"); |
@@ -1910,9 +1918,8 @@ intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) | |||
1910 | OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); | 1918 | OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); |
1911 | } | 1919 | } |
1912 | 1920 | ||
1913 | void | 1921 | void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, |
1914 | intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, | 1922 | u8 *data) |
1915 | u8 *data) | ||
1916 | { | 1923 | { |
1917 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; | 1924 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; |
1918 | int i, j, w = width / 8; | 1925 | int i, j, w = width / 8; |
@@ -1940,8 +1947,8 @@ intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, | |||
1940 | } | 1947 | } |
1941 | } | 1948 | } |
1942 | 1949 | ||
1943 | void | 1950 | void intelfbhw_cursor_reset(struct intelfb_info *dinfo) |
1944 | intelfbhw_cursor_reset(struct intelfb_info *dinfo) { | 1951 | { |
1945 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; | 1952 | u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; |
1946 | int i, j; | 1953 | int i, j; |
1947 | 1954 | ||
@@ -1961,72 +1968,72 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { | |||
1961 | } | 1968 | } |
1962 | } | 1969 | } |
1963 | 1970 | ||
1964 | static irqreturn_t | 1971 | static irqreturn_t intelfbhw_irq(int irq, void *dev_id) |
1965 | intelfbhw_irq(int irq, void *dev_id) { | 1972 | { |
1966 | int handled = 0; | ||
1967 | u16 tmp; | 1973 | u16 tmp; |
1968 | struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; | 1974 | struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; |
1969 | 1975 | ||
1970 | spin_lock(&dinfo->int_lock); | 1976 | spin_lock(&dinfo->int_lock); |
1971 | 1977 | ||
1972 | tmp = INREG16(IIR); | 1978 | tmp = INREG16(IIR); |
1973 | tmp &= VSYNC_PIPE_A_INTERRUPT; | 1979 | if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) |
1980 | tmp &= PIPE_A_EVENT_INTERRUPT; | ||
1981 | else | ||
1982 | tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ | ||
1974 | 1983 | ||
1975 | if (tmp == 0) { | 1984 | if (tmp == 0) { |
1976 | spin_unlock(&dinfo->int_lock); | 1985 | spin_unlock(&dinfo->int_lock); |
1977 | return IRQ_RETVAL(handled); | 1986 | return IRQ_RETVAL(0); /* not us */ |
1978 | } | 1987 | } |
1979 | 1988 | ||
1980 | OUTREG16(IIR, tmp); | 1989 | /* clear status bits 0-15 ASAP and don't touch bits 16-31 */ |
1990 | OUTREG(PIPEASTAT, INREG(PIPEASTAT)); | ||
1981 | 1991 | ||
1982 | if (tmp & VSYNC_PIPE_A_INTERRUPT) { | 1992 | OUTREG16(IIR, tmp); |
1983 | dinfo->vsync.count++; | 1993 | if (dinfo->vsync.pan_display) { |
1984 | if (dinfo->vsync.pan_display) { | 1994 | dinfo->vsync.pan_display = 0; |
1985 | dinfo->vsync.pan_display = 0; | 1995 | OUTREG(DSPABASE, dinfo->vsync.pan_offset); |
1986 | OUTREG(DSPABASE, dinfo->vsync.pan_offset); | ||
1987 | } | ||
1988 | wake_up_interruptible(&dinfo->vsync.wait); | ||
1989 | handled = 1; | ||
1990 | } | 1996 | } |
1991 | 1997 | ||
1998 | dinfo->vsync.count++; | ||
1999 | wake_up_interruptible(&dinfo->vsync.wait); | ||
2000 | |||
1992 | spin_unlock(&dinfo->int_lock); | 2001 | spin_unlock(&dinfo->int_lock); |
1993 | 2002 | ||
1994 | return IRQ_RETVAL(handled); | 2003 | return IRQ_RETVAL(1); |
1995 | } | 2004 | } |
1996 | 2005 | ||
1997 | int | 2006 | int intelfbhw_enable_irq(struct intelfb_info *dinfo) |
1998 | intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { | 2007 | { |
1999 | 2008 | u16 tmp; | |
2000 | if (!test_and_set_bit(0, &dinfo->irq_flags)) { | 2009 | if (!test_and_set_bit(0, &dinfo->irq_flags)) { |
2001 | if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, | 2010 | if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, |
2002 | "intelfb", dinfo)) { | 2011 | "intelfb", dinfo)) { |
2003 | clear_bit(0, &dinfo->irq_flags); | 2012 | clear_bit(0, &dinfo->irq_flags); |
2004 | return -EINVAL; | 2013 | return -EINVAL; |
2005 | } | 2014 | } |
2006 | 2015 | ||
2007 | spin_lock_irq(&dinfo->int_lock); | 2016 | spin_lock_irq(&dinfo->int_lock); |
2008 | OUTREG16(HWSTAM, 0xfffe); | 2017 | OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */ |
2009 | OUTREG16(IMR, 0x0); | 2018 | OUTREG16(IMR, 0); |
2010 | OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); | 2019 | } else |
2011 | spin_unlock_irq(&dinfo->int_lock); | ||
2012 | } else if (reenable) { | ||
2013 | u16 ier; | ||
2014 | |||
2015 | spin_lock_irq(&dinfo->int_lock); | 2020 | spin_lock_irq(&dinfo->int_lock); |
2016 | ier = INREG16(IER); | 2021 | |
2017 | if ((ier & VSYNC_PIPE_A_INTERRUPT)) { | 2022 | if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) |
2018 | DBG_MSG("someone disabled the IRQ [%08X]\n", ier); | 2023 | tmp = PIPE_A_EVENT_INTERRUPT; |
2019 | OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); | 2024 | else |
2020 | } | 2025 | tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ |
2021 | spin_unlock_irq(&dinfo->int_lock); | 2026 | if (tmp != INREG16(IER)) { |
2027 | DBG_MSG("changing IER to 0x%X\n", tmp); | ||
2028 | OUTREG16(IER, tmp); | ||
2022 | } | 2029 | } |
2030 | |||
2031 | spin_unlock_irq(&dinfo->int_lock); | ||
2023 | return 0; | 2032 | return 0; |
2024 | } | 2033 | } |
2025 | 2034 | ||
2026 | void | 2035 | void intelfbhw_disable_irq(struct intelfb_info *dinfo) |
2027 | intelfbhw_disable_irq(struct intelfb_info *dinfo) { | 2036 | { |
2028 | u16 tmp; | ||
2029 | |||
2030 | if (test_and_clear_bit(0, &dinfo->irq_flags)) { | 2037 | if (test_and_clear_bit(0, &dinfo->irq_flags)) { |
2031 | if (dinfo->vsync.pan_display) { | 2038 | if (dinfo->vsync.pan_display) { |
2032 | dinfo->vsync.pan_display = 0; | 2039 | dinfo->vsync.pan_display = 0; |
@@ -2037,16 +2044,15 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) { | |||
2037 | OUTREG16(IMR, 0xffff); | 2044 | OUTREG16(IMR, 0xffff); |
2038 | OUTREG16(IER, 0x0); | 2045 | OUTREG16(IER, 0x0); |
2039 | 2046 | ||
2040 | tmp = INREG16(IIR); | 2047 | OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */ |
2041 | OUTREG16(IIR, tmp); | ||
2042 | spin_unlock_irq(&dinfo->int_lock); | 2048 | spin_unlock_irq(&dinfo->int_lock); |
2043 | 2049 | ||
2044 | free_irq(dinfo->pdev->irq, dinfo); | 2050 | free_irq(dinfo->pdev->irq, dinfo); |
2045 | } | 2051 | } |
2046 | } | 2052 | } |
2047 | 2053 | ||
2048 | int | 2054 | int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) |
2049 | intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { | 2055 | { |
2050 | struct intelfb_vsync *vsync; | 2056 | struct intelfb_vsync *vsync; |
2051 | unsigned int count; | 2057 | unsigned int count; |
2052 | int ret; | 2058 | int ret; |
@@ -2059,18 +2065,16 @@ intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { | |||
2059 | return -ENODEV; | 2065 | return -ENODEV; |
2060 | } | 2066 | } |
2061 | 2067 | ||
2062 | ret = intelfbhw_enable_irq(dinfo, 0); | 2068 | ret = intelfbhw_enable_irq(dinfo); |
2063 | if (ret) { | 2069 | if (ret) |
2064 | return ret; | 2070 | return ret; |
2065 | } | ||
2066 | 2071 | ||
2067 | count = vsync->count; | 2072 | count = vsync->count; |
2068 | ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10); | 2073 | ret = wait_event_interruptible_timeout(vsync->wait, |
2069 | if (ret < 0) { | 2074 | count != vsync->count, HZ / 10); |
2075 | if (ret < 0) | ||
2070 | return ret; | 2076 | return ret; |
2071 | } | ||
2072 | if (ret == 0) { | 2077 | if (ret == 0) { |
2073 | intelfbhw_enable_irq(dinfo, 1); | ||
2074 | DBG_MSG("wait_for_vsync timed out!\n"); | 2078 | DBG_MSG("wait_for_vsync timed out!\n"); |
2075 | return -ETIMEDOUT; | 2079 | return -ETIMEDOUT; |
2076 | } | 2080 | } |
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 8c54ba8fbdda..0b076bac321b 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h | |||
@@ -83,7 +83,7 @@ | |||
83 | */ | 83 | */ |
84 | #define RING_MIN_FREE 64 | 84 | #define RING_MIN_FREE 64 |
85 | 85 | ||
86 | #define IPEHR 0x2088 | 86 | #define IPEHR 0x2088 |
87 | 87 | ||
88 | #define INSTDONE 0x2090 | 88 | #define INSTDONE 0x2090 |
89 | #define PRI_RING_EMPTY 1 | 89 | #define PRI_RING_EMPTY 1 |
@@ -93,7 +93,7 @@ | |||
93 | #define IIR 0x20A4 | 93 | #define IIR 0x20A4 |
94 | #define IMR 0x20A8 | 94 | #define IMR 0x20A8 |
95 | #define VSYNC_PIPE_A_INTERRUPT (1 << 7) | 95 | #define VSYNC_PIPE_A_INTERRUPT (1 << 7) |
96 | #define PIPE_A_EVENT_INTERRUPT (1 << 4) | 96 | #define PIPE_A_EVENT_INTERRUPT (1 << 6) |
97 | #define VSYNC_PIPE_B_INTERRUPT (1 << 5) | 97 | #define VSYNC_PIPE_B_INTERRUPT (1 << 5) |
98 | #define PIPE_B_EVENT_INTERRUPT (1 << 4) | 98 | #define PIPE_B_EVENT_INTERRUPT (1 << 4) |
99 | #define HOST_PORT_EVENT_INTERRUPT (1 << 3) | 99 | #define HOST_PORT_EVENT_INTERRUPT (1 << 3) |
@@ -128,9 +128,9 @@ | |||
128 | 128 | ||
129 | #define GPIOA 0x5010 | 129 | #define GPIOA 0x5010 |
130 | #define GPIOB 0x5014 | 130 | #define GPIOB 0x5014 |
131 | #define GPIOC 0x5018 // this may be external DDC on i830 | 131 | #define GPIOC 0x5018 /* this may be external DDC on i830 */ |
132 | #define GPIOD 0x501C // this is DVO DDC | 132 | #define GPIOD 0x501C /* this is DVO DDC */ |
133 | #define GPIOE 0x5020 // this is DVO i2C | 133 | #define GPIOE 0x5020 /* this is DVO i2C */ |
134 | #define GPIOF 0x5024 | 134 | #define GPIOF 0x5024 |
135 | 135 | ||
136 | /* PLL registers */ | 136 | /* PLL registers */ |
@@ -269,15 +269,20 @@ | |||
269 | #define PORT_ENABLE (1 << 31) | 269 | #define PORT_ENABLE (1 << 31) |
270 | #define PORT_PIPE_SELECT_SHIFT 30 | 270 | #define PORT_PIPE_SELECT_SHIFT 30 |
271 | #define PORT_TV_FLAGS_MASK 0xFF | 271 | #define PORT_TV_FLAGS_MASK 0xFF |
272 | #define PORT_TV_FLAGS 0xC4 // ripped from my BIOS | 272 | #define PORT_TV_FLAGS 0xC4 /* ripped from my BIOS |
273 | // to understand and correct | 273 | to understand and correct */ |
274 | 274 | ||
275 | #define DVOA_SRCDIM 0x61124 | 275 | #define DVOA_SRCDIM 0x61124 |
276 | #define DVOB_SRCDIM 0x61144 | 276 | #define DVOB_SRCDIM 0x61144 |
277 | #define DVOC_SRCDIM 0x61164 | 277 | #define DVOC_SRCDIM 0x61164 |
278 | 278 | ||
279 | #define PIPEA_DSL 0x70000 | ||
280 | #define PIPEB_DSL 0x71000 | ||
279 | #define PIPEACONF 0x70008 | 281 | #define PIPEACONF 0x70008 |
280 | #define PIPEBCONF 0x71008 | 282 | #define PIPEBCONF 0x71008 |
283 | #define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */ | ||
284 | #define PIPEBSTAT 0x71024 | ||
285 | |||
281 | #define PIPECONF_ENABLE (1 << 31) | 286 | #define PIPECONF_ENABLE (1 << 31) |
282 | #define PIPECONF_DISABLE 0 | 287 | #define PIPECONF_DISABLE 0 |
283 | #define PIPECONF_DOUBLE_WIDE (1 << 30) | 288 | #define PIPECONF_DOUBLE_WIDE (1 << 30) |
@@ -286,6 +291,35 @@ | |||
286 | #define PIPECONF_UNLOCKED 0 | 291 | #define PIPECONF_UNLOCKED 0 |
287 | #define PIPECONF_GAMMA (1 << 24) | 292 | #define PIPECONF_GAMMA (1 << 24) |
288 | #define PIPECONF_PALETTE 0 | 293 | #define PIPECONF_PALETTE 0 |
294 | #define PIPECONF_PROGRESSIVE (0 << 21) | ||
295 | #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) | ||
296 | #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) | ||
297 | #define PIPECONF_INTERLACE_MASK (7 << 21) | ||
298 | |||
299 | /* enable bits, write 1 to enable */ | ||
300 | #define PIPESTAT_FIFO_UNDERRUN (1 << 31) | ||
301 | #define PIPESTAT_CRC_ERROR_EN (1 << 29) | ||
302 | #define PIPESTAT_CRC_DONE_EN (1 << 28) | ||
303 | #define PIPESTAT_HOTPLUG_EN (1 << 26) | ||
304 | #define PIPESTAT_VERTICAL_SYNC_EN (1 << 25) | ||
305 | #define PIPESTAT_DISPLINE_COMP_EN (1 << 24) | ||
306 | #define PIPESTAT_FLD_EVT_ODD_EN (1 << 21) | ||
307 | #define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20) | ||
308 | #define PIPESTAT_TV_HOTPLUG_EN (1 << 18) | ||
309 | #define PIPESTAT_VBLANK_EN (1 << 17) | ||
310 | #define PIPESTAT_OVL_UPDATE_EN (1 << 16) | ||
311 | /* status bits, write 1 to clear */ | ||
312 | #define PIPESTAT_HOTPLUG_STATE (1 << 15) | ||
313 | #define PIPESTAT_CRC_ERROR (1 << 13) | ||
314 | #define PIPESTAT_CRC_DONE (1 << 12) | ||
315 | #define PIPESTAT_HOTPLUG (1 << 10) | ||
316 | #define PIPESTAT_VSYNC (1 << 9) | ||
317 | #define PIPESTAT_DISPLINE_COMP (1 << 8) | ||
318 | #define PIPESTAT_FLD_EVT_ODD (1 << 5) | ||
319 | #define PIPESTAT_FLD_EVT_EVEN (1 << 4) | ||
320 | #define PIPESTAT_TV_HOTPLUG (1 << 2) | ||
321 | #define PIPESTAT_VBLANK (1 << 1) | ||
322 | #define PIPESTAT_OVL_UPDATE (1 << 0) | ||
289 | 323 | ||
290 | #define DISPARB 0x70030 | 324 | #define DISPARB 0x70030 |
291 | #define DISPARB_AEND_MASK 0x1ff | 325 | #define DISPARB_AEND_MASK 0x1ff |
@@ -365,7 +399,7 @@ | |||
365 | #define DISPPLANE_8BPP (0x2<<26) | 399 | #define DISPPLANE_8BPP (0x2<<26) |
366 | #define DISPPLANE_15_16BPP (0x4<<26) | 400 | #define DISPPLANE_15_16BPP (0x4<<26) |
367 | #define DISPPLANE_16BPP (0x5<<26) | 401 | #define DISPPLANE_16BPP (0x5<<26) |
368 | #define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) | 402 | #define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) |
369 | #define DISPPLANE_32BPP (0x7<<26) | 403 | #define DISPPLANE_32BPP (0x7<<26) |
370 | #define DISPPLANE_STEREO_ENABLE (1<<25) | 404 | #define DISPPLANE_STEREO_ENABLE (1<<25) |
371 | #define DISPPLANE_STEREO_DISABLE 0 | 405 | #define DISPPLANE_STEREO_DISABLE 0 |
@@ -567,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, | |||
567 | extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, | 601 | extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, |
568 | int height, u8 *data); | 602 | int height, u8 *data); |
569 | extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); | 603 | extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); |
570 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); | 604 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); |
571 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); | 605 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); |
572 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); | 606 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); |
573 | 607 | ||
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c index 1c5579907397..acb9370fdb14 100644 --- a/drivers/video/kyro/fbdev.c +++ b/drivers/video/kyro/fbdev.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <asm/io.h> | 23 | #include <asm/io.h> |
24 | #include <asm/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #ifdef CONFIG_MTRR | 25 | #ifdef CONFIG_MTRR |
26 | #include <asm/mtrr.h> | 26 | #include <asm/mtrr.h> |
27 | #endif | 27 | #endif |
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 2b0f799aa8da..a9283bae7790 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c | |||
@@ -34,6 +34,10 @@ extern const struct linux_logo logo_superh_vga16; | |||
34 | extern const struct linux_logo logo_superh_clut224; | 34 | extern const struct linux_logo logo_superh_clut224; |
35 | extern const struct linux_logo logo_m32r_clut224; | 35 | extern const struct linux_logo logo_m32r_clut224; |
36 | 36 | ||
37 | static int nologo; | ||
38 | module_param(nologo, bool, 0); | ||
39 | MODULE_PARM_DESC(nologo, "Disables startup logo"); | ||
40 | |||
37 | /* logo's are marked __initdata. Use __init_refok to tell | 41 | /* logo's are marked __initdata. Use __init_refok to tell |
38 | * modpost that it is intended that this function uses data | 42 | * modpost that it is intended that this function uses data |
39 | * marked __initdata. | 43 | * marked __initdata. |
@@ -42,6 +46,9 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) | |||
42 | { | 46 | { |
43 | const struct linux_logo *logo = NULL; | 47 | const struct linux_logo *logo = NULL; |
44 | 48 | ||
49 | if (nologo) | ||
50 | return NULL; | ||
51 | |||
45 | if (depth >= 1) { | 52 | if (depth >= 1) { |
46 | #ifdef CONFIG_LOGO_LINUX_MONO | 53 | #ifdef CONFIG_LOGO_LINUX_MONO |
47 | /* Generic Linux logo */ | 54 | /* Generic Linux logo */ |
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 86ca7b179000..b25972ac6eeb 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c | |||
@@ -113,7 +113,7 @@ | |||
113 | #include "matroxfb_g450.h" | 113 | #include "matroxfb_g450.h" |
114 | #include <linux/matroxfb.h> | 114 | #include <linux/matroxfb.h> |
115 | #include <linux/interrupt.h> | 115 | #include <linux/interrupt.h> |
116 | #include <asm/uaccess.h> | 116 | #include <linux/uaccess.h> |
117 | 117 | ||
118 | #ifdef CONFIG_PPC_PMAC | 118 | #ifdef CONFIG_PPC_PMAC |
119 | #include <asm/machdep.h> | 119 | #include <asm/machdep.h> |
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 4b3344e03695..a6ab5b6a58d0 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include "matroxfb_misc.h" | 15 | #include "matroxfb_misc.h" |
16 | #include "matroxfb_DAC1064.h" | 16 | #include "matroxfb_DAC1064.h" |
17 | #include <linux/matroxfb.h> | 17 | #include <linux/matroxfb.h> |
18 | #include <asm/uaccess.h> | 18 | #include <linux/uaccess.h> |
19 | 19 | ||
20 | /* **************************************************** */ | 20 | /* **************************************************** */ |
21 | 21 | ||
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c index 4d610b405d45..6209a761f674 100644 --- a/drivers/video/matrox/matroxfb_g450.c +++ b/drivers/video/matrox/matroxfb_g450.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include "matroxfb_DAC1064.h" | 17 | #include "matroxfb_DAC1064.h" |
18 | #include "g450_pll.h" | 18 | #include "g450_pll.h" |
19 | #include <linux/matroxfb.h> | 19 | #include <linux/matroxfb.h> |
20 | #include <asm/uaccess.h> | ||
21 | #include <asm/div64.h> | 20 | #include <asm/div64.h> |
22 | 21 | ||
23 | #include "matroxfb_g450.h" | 22 | #include "matroxfb_g450.h" |
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index de0d755f9019..49cd53e46c0a 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/matroxfb.h> | 19 | #include <linux/matroxfb.h> |
20 | #include <asm/div64.h> | 20 | #include <asm/div64.h> |
21 | #include <asm/uaccess.h> | ||
22 | 21 | ||
23 | #define MAVEN_I2CID (0x1B) | 22 | #define MAVEN_I2CID (0x1B) |
24 | 23 | ||
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 980d5f623902..80cd117ca65c 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/video/mbx/mbxfb.c | 2 | * linux/drivers/video/mbx/mbxfb.c |
3 | * | 3 | * |
4 | * Copyright (C) 2006 8D Technologies inc | 4 | * Copyright (C) 2006-2007 8D Technologies inc |
5 | * Raphael Assenat <raph@8d.com> | 5 | * Raphael Assenat <raph@8d.com> |
6 | * - Added video overlay support | 6 | * - Added video overlay support |
7 | * - Various improvements | 7 | * - Various improvements |
@@ -334,8 +334,8 @@ static int mbxfb_blank(int blank, struct fb_info *info) | |||
334 | 334 | ||
335 | static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | 335 | static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) |
336 | { | 336 | { |
337 | u32 vsctrl, vbbase, vscadr, vsadr; | 337 | u32 vsctrl, vscadr, vsadr; |
338 | u32 sssize, spoctrl, svctrl, shctrl; | 338 | u32 sssize, spoctrl, shctrl; |
339 | u32 vubase, vvbase; | 339 | u32 vubase, vvbase; |
340 | u32 vovrclk; | 340 | u32 vovrclk; |
341 | 341 | ||
@@ -349,13 +349,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
349 | vscadr = readl(VSCADR); | 349 | vscadr = readl(VSCADR); |
350 | vubase = readl(VUBASE); | 350 | vubase = readl(VUBASE); |
351 | vvbase = readl(VVBASE); | 351 | vvbase = readl(VVBASE); |
352 | shctrl = readl(SHCTRL); | ||
352 | 353 | ||
353 | spoctrl = readl(SPOCTRL); | 354 | spoctrl = readl(SPOCTRL); |
354 | sssize = readl(SSSIZE); | 355 | sssize = readl(SSSIZE); |
355 | 356 | ||
356 | |||
357 | vbbase = Vbbase_Glalpha(set->alpha); | ||
358 | |||
359 | vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) | | 357 | vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) | |
360 | FMsk(VSCTRL_VSHEIGHT) | | 358 | FMsk(VSCTRL_VSHEIGHT) | |
361 | FMsk(VSCTRL_VPIXFMT) | | 359 | FMsk(VSCTRL_VPIXFMT) | |
@@ -364,38 +362,41 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
364 | vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) | | 362 | vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) | |
365 | VSCTRL_CSC_EN; | 363 | VSCTRL_CSC_EN; |
366 | 364 | ||
367 | vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC | | 365 | vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) ); |
368 | FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) | | ||
369 | FMsk(VSCADR_VBASE_ADR) ); | ||
370 | vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); | 366 | vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); |
371 | vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); | 367 | vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); |
372 | 368 | ||
373 | switch (set->fmt) | 369 | switch (set->fmt) { |
374 | { | 370 | case MBXFB_FMT_YUV16: |
375 | case MBXFB_FMT_YUV12: | 371 | vsctrl |= VSCTRL_VPIXFMT_YUV12; |
376 | vsctrl |= VSCTRL_VPIXFMT_YUV12; | ||
377 | 372 | ||
378 | set->Y_stride = ((set->width) + 0xf ) & ~0xf; | 373 | set->Y_stride = ((set->width) + 0xf ) & ~0xf; |
374 | break; | ||
375 | case MBXFB_FMT_YUV12: | ||
376 | vsctrl |= VSCTRL_VPIXFMT_YUV12; | ||
379 | 377 | ||
378 | set->Y_stride = ((set->width) + 0xf ) & ~0xf; | ||
379 | vubase |= VUBASE_UVHALFSTR; | ||
380 | |||
381 | break; | ||
382 | case MBXFB_FMT_UY0VY1: | ||
383 | vsctrl |= VSCTRL_VPIXFMT_UY0VY1; | ||
384 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
385 | break; | ||
386 | case MBXFB_FMT_VY0UY1: | ||
387 | vsctrl |= VSCTRL_VPIXFMT_VY0UY1; | ||
388 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
389 | break; | ||
390 | case MBXFB_FMT_Y0UY1V: | ||
391 | vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; | ||
392 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
393 | break; | ||
394 | case MBXFB_FMT_Y0VY1U: | ||
395 | vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; | ||
396 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
380 | break; | 397 | break; |
381 | case MBXFB_FMT_UY0VY1: | 398 | default: |
382 | vsctrl |= VSCTRL_VPIXFMT_UY0VY1; | 399 | return -EINVAL; |
383 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
384 | break; | ||
385 | case MBXFB_FMT_VY0UY1: | ||
386 | vsctrl |= VSCTRL_VPIXFMT_VY0UY1; | ||
387 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
388 | break; | ||
389 | case MBXFB_FMT_Y0UY1V: | ||
390 | vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; | ||
391 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
392 | break; | ||
393 | case MBXFB_FMT_Y0VY1U: | ||
394 | vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; | ||
395 | set->Y_stride = (set->width*2 + 0xf ) & ~0xf; | ||
396 | break; | ||
397 | default: | ||
398 | return -EINVAL; | ||
399 | } | 400 | } |
400 | 401 | ||
401 | /* VSCTRL has the bits which sets the Video Pixel Format. | 402 | /* VSCTRL has the bits which sets the Video Pixel Format. |
@@ -417,8 +418,7 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
417 | (0x60000 + set->mem_offset + set->V_offset)>>3); | 418 | (0x60000 + set->mem_offset + set->V_offset)>>3); |
418 | 419 | ||
419 | 420 | ||
420 | vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB | | 421 | vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); |
421 | Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); | ||
422 | 422 | ||
423 | if (set->enable) | 423 | if (set->enable) |
424 | vscadr |= VSCADR_STR_EN; | 424 | vscadr |= VSCADR_STR_EN; |
@@ -433,9 +433,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
433 | 433 | ||
434 | spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | | 434 | spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | |
435 | SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C | | 435 | SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C | |
436 | FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH)); | 436 | FMsk(SPOCTRL_VPITCH)); |
437 | spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height) | 437 | spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height); |
438 | | SPOCTRL_VORDER_2TAP; | ||
439 | 438 | ||
440 | /* Bypass horiz/vert scaler when same size */ | 439 | /* Bypass horiz/vert scaler when same size */ |
441 | if (set->scaled_width == set->width) | 440 | if (set->scaled_width == set->width) |
@@ -443,14 +442,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
443 | if (set->scaled_height == set->height) | 442 | if (set->scaled_height == set->height) |
444 | spoctrl |= SPOCTRL_V_SC_BP; | 443 | spoctrl |= SPOCTRL_V_SC_BP; |
445 | 444 | ||
446 | svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); | 445 | shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM); |
447 | 446 | shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width); | |
448 | shctrl = Shctrl_Hinitial(4<<11) | ||
449 | | Shctrl_Hpitch((set->width<<11)/set->scaled_width); | ||
450 | 447 | ||
451 | /* Video plane registers */ | 448 | /* Video plane registers */ |
452 | write_reg(vsctrl, VSCTRL); | 449 | write_reg(vsctrl, VSCTRL); |
453 | write_reg(vbbase, VBBASE); | ||
454 | write_reg(vscadr, VSCADR); | 450 | write_reg(vscadr, VSCADR); |
455 | write_reg(vubase, VUBASE); | 451 | write_reg(vubase, VUBASE); |
456 | write_reg(vvbase, VVBASE); | 452 | write_reg(vvbase, VVBASE); |
@@ -459,28 +455,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
459 | /* Video scaler registers */ | 455 | /* Video scaler registers */ |
460 | write_reg(sssize, SSSIZE); | 456 | write_reg(sssize, SSSIZE); |
461 | write_reg(spoctrl, SPOCTRL); | 457 | write_reg(spoctrl, SPOCTRL); |
462 | write_reg(svctrl, SVCTRL); | ||
463 | write_reg(shctrl, SHCTRL); | 458 | write_reg(shctrl, SHCTRL); |
464 | 459 | ||
465 | /* RAPH: Using those coefficients, the scaled | ||
466 | * image is quite blurry. I dont know how | ||
467 | * to improve them ; The chip documentation | ||
468 | * was not helpful.. */ | ||
469 | write_reg(0x21212121, VSCOEFF0); | ||
470 | write_reg(0x21212121, VSCOEFF1); | ||
471 | write_reg(0x21212121, VSCOEFF2); | ||
472 | write_reg(0x21212121, VSCOEFF3); | ||
473 | write_reg(0x21212121, VSCOEFF4); | ||
474 | write_reg(0x00000000, HSCOEFF0); | ||
475 | write_reg(0x00000000, HSCOEFF1); | ||
476 | write_reg(0x00000000, HSCOEFF2); | ||
477 | write_reg(0x03020201, HSCOEFF3); | ||
478 | write_reg(0x09070604, HSCOEFF4); | ||
479 | write_reg(0x0f0e0c0a, HSCOEFF5); | ||
480 | write_reg(0x15141211, HSCOEFF6); | ||
481 | write_reg(0x19181716, HSCOEFF7); | ||
482 | write_reg(0x00000019, HSCOEFF8); | ||
483 | |||
484 | /* Clock */ | 460 | /* Clock */ |
485 | if (set->enable) | 461 | if (set->enable) |
486 | vovrclk |= 1; | 462 | vovrclk |= 1; |
@@ -492,27 +468,206 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | |||
492 | return 0; | 468 | return 0; |
493 | } | 469 | } |
494 | 470 | ||
471 | static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder) | ||
472 | { | ||
473 | unsigned long gscadr, vscadr; | ||
474 | |||
475 | if (porder->bottom == porder->top) | ||
476 | return -EINVAL; | ||
477 | |||
478 | gscadr = readl(GSCADR); | ||
479 | vscadr = readl(VSCADR); | ||
480 | |||
481 | gscadr &= ~(FMsk(GSCADR_BLEND_POS)); | ||
482 | vscadr &= ~(FMsk(VSCADR_BLEND_POS)); | ||
483 | |||
484 | switch (porder->bottom) { | ||
485 | case MBXFB_PLANE_GRAPHICS: | ||
486 | gscadr |= GSCADR_BLEND_GFX; | ||
487 | break; | ||
488 | case MBXFB_PLANE_VIDEO: | ||
489 | vscadr |= VSCADR_BLEND_GFX; | ||
490 | break; | ||
491 | default: | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | switch (porder->top) { | ||
496 | case MBXFB_PLANE_GRAPHICS: | ||
497 | gscadr |= GSCADR_BLEND_VID; | ||
498 | break; | ||
499 | case MBXFB_PLANE_VIDEO: | ||
500 | vscadr |= GSCADR_BLEND_VID; | ||
501 | break; | ||
502 | default: | ||
503 | return -EINVAL; | ||
504 | } | ||
505 | |||
506 | write_reg_dly(vscadr, VSCADR); | ||
507 | write_reg_dly(gscadr, GSCADR); | ||
508 | |||
509 | return 0; | ||
510 | |||
511 | } | ||
512 | |||
513 | static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha) | ||
514 | { | ||
515 | unsigned long vscadr, vbbase, vcmsk; | ||
516 | unsigned long gscadr, gbbase, gdrctrl; | ||
517 | |||
518 | vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) | | ||
519 | Vbbase_Colkey(alpha->overlay_colorkey); | ||
520 | |||
521 | gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) | | ||
522 | Gbbase_Colkey(alpha->graphics_colorkey); | ||
523 | |||
524 | vcmsk = readl(VCMSK); | ||
525 | vcmsk &= ~(FMsk(VCMSK_COLKEY_M)); | ||
526 | vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask); | ||
527 | |||
528 | gdrctrl = readl(GDRCTRL); | ||
529 | gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM)); | ||
530 | gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask); | ||
531 | |||
532 | vscadr = readl(VSCADR); | ||
533 | vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN); | ||
534 | |||
535 | gscadr = readl(GSCADR); | ||
536 | gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC); | ||
537 | |||
538 | switch (alpha->overlay_colorkey_mode) { | ||
539 | case MBXFB_COLORKEY_DISABLED: | ||
540 | break; | ||
541 | case MBXFB_COLORKEY_PREVIOUS: | ||
542 | vscadr |= VSCADR_COLKEY_EN; | ||
543 | break; | ||
544 | case MBXFB_COLORKEY_CURRENT: | ||
545 | vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC; | ||
546 | break; | ||
547 | default: | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | |||
551 | switch (alpha->overlay_blend_mode) { | ||
552 | case MBXFB_ALPHABLEND_NONE: | ||
553 | vscadr |= VSCADR_BLEND_NONE; | ||
554 | break; | ||
555 | case MBXFB_ALPHABLEND_GLOBAL: | ||
556 | vscadr |= VSCADR_BLEND_GLOB; | ||
557 | break; | ||
558 | case MBXFB_ALPHABLEND_PIXEL: | ||
559 | vscadr |= VSCADR_BLEND_PIX; | ||
560 | break; | ||
561 | default: | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | switch (alpha->graphics_colorkey_mode) { | ||
566 | case MBXFB_COLORKEY_DISABLED: | ||
567 | break; | ||
568 | case MBXFB_COLORKEY_PREVIOUS: | ||
569 | gscadr |= GSCADR_COLKEY_EN; | ||
570 | break; | ||
571 | case MBXFB_COLORKEY_CURRENT: | ||
572 | gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC; | ||
573 | break; | ||
574 | default: | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | switch (alpha->graphics_blend_mode) { | ||
579 | case MBXFB_ALPHABLEND_NONE: | ||
580 | gscadr |= GSCADR_BLEND_NONE; | ||
581 | break; | ||
582 | case MBXFB_ALPHABLEND_GLOBAL: | ||
583 | gscadr |= GSCADR_BLEND_GLOB; | ||
584 | break; | ||
585 | case MBXFB_ALPHABLEND_PIXEL: | ||
586 | gscadr |= GSCADR_BLEND_PIX; | ||
587 | break; | ||
588 | default: | ||
589 | return -EINVAL; | ||
590 | } | ||
591 | |||
592 | write_reg_dly(vbbase, VBBASE); | ||
593 | write_reg_dly(gbbase, GBBASE); | ||
594 | write_reg_dly(vcmsk, VCMSK); | ||
595 | write_reg_dly(gdrctrl, GDRCTRL); | ||
596 | write_reg_dly(gscadr, GSCADR); | ||
597 | write_reg_dly(vscadr, VSCADR); | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
495 | static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, | 602 | static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, |
496 | unsigned long arg) | 603 | unsigned long arg) |
497 | { | 604 | { |
498 | struct mbxfb_overlaySetup setup; | 605 | struct mbxfb_overlaySetup setup; |
606 | struct mbxfb_planeorder porder; | ||
607 | struct mbxfb_alphaCtl alpha; | ||
608 | struct mbxfb_reg reg; | ||
499 | int res; | 609 | int res; |
610 | __u32 tmp; | ||
500 | 611 | ||
501 | if (cmd == MBXFB_IOCX_OVERLAY) | 612 | switch (cmd) |
502 | { | 613 | { |
503 | if (copy_from_user(&setup, (void __user*)arg, | 614 | case MBXFB_IOCX_OVERLAY: |
504 | sizeof(struct mbxfb_overlaySetup))) | 615 | if (copy_from_user(&setup, (void __user*)arg, |
616 | sizeof(struct mbxfb_overlaySetup))) | ||
617 | return -EFAULT; | ||
618 | |||
619 | res = mbxfb_setupOverlay(&setup); | ||
620 | if (res) | ||
621 | return res; | ||
622 | |||
623 | if (copy_to_user((void __user*)arg, &setup, | ||
624 | sizeof(struct mbxfb_overlaySetup))) | ||
625 | return -EFAULT; | ||
626 | |||
627 | return 0; | ||
628 | |||
629 | case MBXFB_IOCS_PLANEORDER: | ||
630 | if (copy_from_user(&porder, (void __user*)arg, | ||
631 | sizeof(struct mbxfb_planeorder))) | ||
505 | return -EFAULT; | 632 | return -EFAULT; |
506 | 633 | ||
507 | res = mbxfb_setupOverlay(&setup); | 634 | return mbxfb_ioctl_planeorder(&porder); |
508 | if (res) | ||
509 | return res; | ||
510 | 635 | ||
511 | if (copy_to_user((void __user*)arg, &setup, | 636 | case MBXFB_IOCS_ALPHA: |
512 | sizeof(struct mbxfb_overlaySetup))) | 637 | if (copy_from_user(&alpha, (void __user*)arg, |
638 | sizeof(struct mbxfb_alphaCtl))) | ||
513 | return -EFAULT; | 639 | return -EFAULT; |
514 | 640 | ||
515 | return 0; | 641 | return mbxfb_ioctl_alphactl(&alpha); |
642 | |||
643 | case MBXFB_IOCS_REG: | ||
644 | if (copy_from_user(®, (void __user*)arg, | ||
645 | sizeof(struct mbxfb_reg))) | ||
646 | return -EFAULT; | ||
647 | |||
648 | if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ | ||
649 | return -EINVAL; | ||
650 | |||
651 | tmp = readl(virt_base_2700 + reg.addr); | ||
652 | tmp &= ~reg.mask; | ||
653 | tmp |= reg.val & reg.mask; | ||
654 | writel(tmp, virt_base_2700 + reg.addr); | ||
655 | |||
656 | return 0; | ||
657 | case MBXFB_IOCX_REG: | ||
658 | if (copy_from_user(®, (void __user*)arg, | ||
659 | sizeof(struct mbxfb_reg))) | ||
660 | return -EFAULT; | ||
661 | |||
662 | if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ | ||
663 | return -EINVAL; | ||
664 | reg.val = readl(virt_base_2700 + reg.addr); | ||
665 | |||
666 | if (copy_to_user((void __user*)arg, ®, | ||
667 | sizeof(struct mbxfb_reg))) | ||
668 | return -EFAULT; | ||
669 | |||
670 | return 0; | ||
516 | } | 671 | } |
517 | return -EINVAL; | 672 | return -EINVAL; |
518 | } | 673 | } |
@@ -558,7 +713,6 @@ static void __devinit setup_memc(struct fb_info *fbi) | |||
558 | LMTYPE); | 713 | LMTYPE); |
559 | /* enable memory controller */ | 714 | /* enable memory controller */ |
560 | write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); | 715 | write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); |
561 | |||
562 | /* perform dummy reads */ | 716 | /* perform dummy reads */ |
563 | for ( i = 0; i < 16; i++ ) { | 717 | for ( i = 0; i < 16; i++ ) { |
564 | tmp = readl(fbi->screen_base); | 718 | tmp = readl(fbi->screen_base); |
@@ -588,8 +742,8 @@ static void enable_clocks(struct fb_info *fbi) | |||
588 | write_reg_dly(0x00000000, VOVRCLK); | 742 | write_reg_dly(0x00000000, VOVRCLK); |
589 | write_reg_dly(PIXCLK_EN, PIXCLK); | 743 | write_reg_dly(PIXCLK_EN, PIXCLK); |
590 | write_reg_dly(MEMCLK_EN, MEMCLK); | 744 | write_reg_dly(MEMCLK_EN, MEMCLK); |
591 | write_reg_dly(0x00000006, M24CLK); | 745 | write_reg_dly(0x00000001, M24CLK); |
592 | write_reg_dly(0x00000006, MBXCLK); | 746 | write_reg_dly(0x00000001, MBXCLK); |
593 | write_reg_dly(SDCLK_EN, SDCLK); | 747 | write_reg_dly(SDCLK_EN, SDCLK); |
594 | write_reg_dly(0x00000001, PIXCLKDIV); | 748 | write_reg_dly(0x00000001, PIXCLKDIV); |
595 | } | 749 | } |
@@ -597,6 +751,7 @@ static void enable_clocks(struct fb_info *fbi) | |||
597 | static void __devinit setup_graphics(struct fb_info *fbi) | 751 | static void __devinit setup_graphics(struct fb_info *fbi) |
598 | { | 752 | { |
599 | unsigned long gsctrl; | 753 | unsigned long gsctrl; |
754 | unsigned long vscadr; | ||
600 | 755 | ||
601 | gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | | 756 | gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | |
602 | Gsctrl_Height(fbi->var.yres); | 757 | Gsctrl_Height(fbi->var.yres); |
@@ -620,6 +775,11 @@ static void __devinit setup_graphics(struct fb_info *fbi) | |||
620 | write_reg_dly(0x00ffffff, GDRCTRL); | 775 | write_reg_dly(0x00ffffff, GDRCTRL); |
621 | write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); | 776 | write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); |
622 | write_reg_dly(0x00000000, GPLUT); | 777 | write_reg_dly(0x00000000, GPLUT); |
778 | |||
779 | vscadr = readl(VSCADR); | ||
780 | vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M)); | ||
781 | vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE; | ||
782 | write_reg_dly(vscadr, VSCADR); | ||
623 | } | 783 | } |
624 | 784 | ||
625 | static void __devinit setup_display(struct fb_info *fbi) | 785 | static void __devinit setup_display(struct fb_info *fbi) |
@@ -638,13 +798,47 @@ static void __devinit setup_display(struct fb_info *fbi) | |||
638 | 798 | ||
639 | static void __devinit enable_controller(struct fb_info *fbi) | 799 | static void __devinit enable_controller(struct fb_info *fbi) |
640 | { | 800 | { |
801 | u32 svctrl, shctrl; | ||
802 | |||
641 | write_reg_dly(SYSRST_RST, SYSRST); | 803 | write_reg_dly(SYSRST_RST, SYSRST); |
642 | 804 | ||
805 | /* setup a timeout, raise drive strength */ | ||
806 | write_reg_dly(0xffffff0c, SYSCFG); | ||
643 | 807 | ||
644 | enable_clocks(fbi); | 808 | enable_clocks(fbi); |
645 | setup_memc(fbi); | 809 | setup_memc(fbi); |
646 | setup_graphics(fbi); | 810 | setup_graphics(fbi); |
647 | setup_display(fbi); | 811 | setup_display(fbi); |
812 | |||
813 | shctrl = readl(SHCTRL); | ||
814 | shctrl &= ~(FMsk(SHCTRL_HINITIAL)); | ||
815 | shctrl |= Shctrl_Hinitial(4<<11); | ||
816 | writel(shctrl, SHCTRL); | ||
817 | |||
818 | svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); | ||
819 | writel(svctrl, SVCTRL); | ||
820 | |||
821 | writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP | ||
822 | , SPOCTRL); | ||
823 | |||
824 | /* Those coefficients are good for scaling up. For scaling | ||
825 | * down, the application has to calculate them. */ | ||
826 | write_reg(0xff000100, VSCOEFF0); | ||
827 | write_reg(0xfdfcfdfe, VSCOEFF1); | ||
828 | write_reg(0x170d0500, VSCOEFF2); | ||
829 | write_reg(0x3d372d22, VSCOEFF3); | ||
830 | write_reg(0x00000040, VSCOEFF4); | ||
831 | |||
832 | write_reg(0xff010100, HSCOEFF0); | ||
833 | write_reg(0x00000000, HSCOEFF1); | ||
834 | write_reg(0x02010000, HSCOEFF2); | ||
835 | write_reg(0x01020302, HSCOEFF3); | ||
836 | write_reg(0xf9fbfe00, HSCOEFF4); | ||
837 | write_reg(0xfbf7f6f7, HSCOEFF5); | ||
838 | write_reg(0x1c110700, HSCOEFF6); | ||
839 | write_reg(0x3e393127, HSCOEFF7); | ||
840 | write_reg(0x00000040, HSCOEFF8); | ||
841 | |||
648 | } | 842 | } |
649 | 843 | ||
650 | #ifdef CONFIG_PM | 844 | #ifdef CONFIG_PM |
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h index 9a24fb0c7d48..5f14b4befd71 100644 --- a/drivers/video/mbx/reg_bits.h +++ b/drivers/video/mbx/reg_bits.h | |||
@@ -215,7 +215,7 @@ | |||
215 | /* GSCADR graphics stream control address register fields */ | 215 | /* GSCADR graphics stream control address register fields */ |
216 | #define GSCADR_STR_EN (1 << 31) | 216 | #define GSCADR_STR_EN (1 << 31) |
217 | #define GSCADR_COLKEY_EN (1 << 30) | 217 | #define GSCADR_COLKEY_EN (1 << 30) |
218 | #define GSCADR_COLKEYSCR (1 << 29) | 218 | #define GSCADR_COLKEYSRC (1 << 29) |
219 | #define GSCADR_BLEND_M Fld(2,27) | 219 | #define GSCADR_BLEND_M Fld(2,27) |
220 | #define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M)) | 220 | #define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M)) |
221 | #define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M)) | 221 | #define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M)) |
@@ -303,6 +303,67 @@ | |||
303 | #define VSADR_YSTART Fld(11,0) | 303 | #define VSADR_YSTART Fld(11,0) |
304 | #define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART)) | 304 | #define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART)) |
305 | 305 | ||
306 | /* VSCTRL - Video Surface Control Register */ | ||
307 | #define VSCTRL_VPIXFMT Fld(4,27) | ||
308 | #define VSCTRL_VPIXFMT_YUV12 ((0x9) << FShft(VSCTRL_VPIXFMT)) | ||
309 | #define VSCTRL_VPIXFMT_UY0VY1 ((0xc) << FShft(VSCTRL_VPIXFMT)) | ||
310 | #define VSCTRL_VPIXFMT_VY0UY1 ((0xd) << FShft(VSCTRL_VPIXFMT)) | ||
311 | #define VSCTRL_VPIXFMT_Y0UY1V ((0xe) << FShft(VSCTRL_VPIXFMT)) | ||
312 | #define VSCTRL_VPIXFMT_Y0VY1U ((0xf) << FShft(VSCTRL_VPIXFMT)) | ||
313 | #define VSCTRL_GAMMA_EN (1 << 26) | ||
314 | #define VSCTRL_CSC_EN (1 << 25) | ||
315 | #define VSCTRL_COSITED (1 << 22) | ||
316 | #define VSCTRL_VSWIDTH Fld(11,11) | ||
317 | #define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \ | ||
318 | (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH)) | ||
319 | #define VSCTRL_VSHEIGHT Fld(11,0) | ||
320 | #define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \ | ||
321 | (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT)) | ||
322 | |||
323 | /* VBBASE - Video Blending Base Register */ | ||
324 | #define VBBASE_GLALPHA Fld(8,24) | ||
325 | #define Vbbase_Glalpha(x) ((x) << FShft(VBBASE_GLALPHA)) | ||
326 | |||
327 | #define VBBASE_COLKEY Fld(24,0) | ||
328 | #define Vbbase_Colkey(x) ((x) << FShft(VBBASE_COLKEY)) | ||
329 | |||
330 | /* VCMSK - Video Color Key Mask Register */ | ||
331 | #define VCMSK_COLKEY_M Fld(24,0) | ||
332 | #define Vcmsk_colkey_m(x) ((x) << FShft(VCMSK_COLKEY_M)) | ||
333 | |||
334 | /* VSCADR - Video Stream Control Rddress Register */ | ||
335 | #define VSCADR_STR_EN (1 << 31) | ||
336 | #define VSCADR_COLKEY_EN (1 << 30) | ||
337 | #define VSCADR_COLKEYSRC (1 << 29) | ||
338 | #define VSCADR_BLEND_M Fld(2,27) | ||
339 | #define VSCADR_BLEND_NONE ((0x0) << FShft(VSCADR_BLEND_M)) | ||
340 | #define VSCADR_BLEND_INV ((0x1) << FShft(VSCADR_BLEND_M)) | ||
341 | #define VSCADR_BLEND_GLOB ((0x2) << FShft(VSCADR_BLEND_M)) | ||
342 | #define VSCADR_BLEND_PIX ((0x3) << FShft(VSCADR_BLEND_M)) | ||
343 | #define VSCADR_BLEND_POS Fld(2,24) | ||
344 | #define VSCADR_BLEND_GFX ((0x0) << FShft(VSCADR_BLEND_POS)) | ||
345 | #define VSCADR_BLEND_VID ((0x1) << FShft(VSCADR_BLEND_POS)) | ||
346 | #define VSCADR_BLEND_CUR ((0x2) << FShft(VSCADR_BLEND_POS)) | ||
347 | #define VSCADR_VBASE_ADR Fld(23,0) | ||
348 | #define Vscadr_Vbase_Adr(x) ((x) << FShft(VSCADR_VBASE_ADR)) | ||
349 | |||
350 | /* VUBASE - Video U Base Register */ | ||
351 | #define VUBASE_UVHALFSTR (1 << 31) | ||
352 | #define VUBASE_UBASE_ADR Fld(24,0) | ||
353 | #define Vubase_Ubase_Adr(x) ((x) << FShft(VUBASE_UBASE_ADR)) | ||
354 | |||
355 | /* VVBASE - Video V Base Register */ | ||
356 | #define VVBASE_VBASE_ADR Fld(24,0) | ||
357 | #define Vvbase_Vbase_Adr(x) ((x) << FShft(VVBASE_VBASE_ADR)) | ||
358 | |||
359 | /* VSADR - Video Stride Address Register */ | ||
360 | #define VSADR_SRCSTRIDE Fld(10,22) | ||
361 | #define Vsadr_Srcstride(x) ((x) << FShft(VSADR_SRCSTRIDE)) | ||
362 | #define VSADR_XSTART Fld(11,11) | ||
363 | #define Vsadr_Xstart(x) ((x) << FShft(VSADR_XSTART)) | ||
364 | #define VSADR_YSTART Fld(11,0) | ||
365 | #define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART)) | ||
366 | |||
306 | /* HCCTRL - Hardware Cursor Register fields */ | 367 | /* HCCTRL - Hardware Cursor Register fields */ |
307 | #define HCCTRL_CUR_EN (1 << 31) | 368 | #define HCCTRL_CUR_EN (1 << 31) |
308 | #define HCCTRL_COLKEY_EN (1 << 29) | 369 | #define HCCTRL_COLKEY_EN (1 << 29) |
@@ -479,6 +540,30 @@ | |||
479 | #define DINTRE_HBLNK1_EN (1 << 1) | 540 | #define DINTRE_HBLNK1_EN (1 << 1) |
480 | #define DINTRE_HBLNK0_EN (1 << 0) | 541 | #define DINTRE_HBLNK0_EN (1 << 0) |
481 | 542 | ||
543 | /* DINTRS - Display Interrupt Status Register */ | ||
544 | #define DINTRS_CUR_OR_S (1 << 18) | ||
545 | #define DINTRS_STR2_OR_S (1 << 17) | ||
546 | #define DINTRS_STR1_OR_S (1 << 16) | ||
547 | #define DINTRS_CUR_UR_S (1 << 6) | ||
548 | #define DINTRS_STR2_UR_S (1 << 5) | ||
549 | #define DINTRS_STR1_UR_S (1 << 4) | ||
550 | #define DINTRS_VEVENT1_S (1 << 3) | ||
551 | #define DINTRS_VEVENT0_S (1 << 2) | ||
552 | #define DINTRS_HBLNK1_S (1 << 1) | ||
553 | #define DINTRS_HBLNK0_S (1 << 0) | ||
554 | |||
555 | /* DINTRE - Display Interrupt Enable Register */ | ||
556 | #define DINTRE_CUR_OR_EN (1 << 18) | ||
557 | #define DINTRE_STR2_OR_EN (1 << 17) | ||
558 | #define DINTRE_STR1_OR_EN (1 << 16) | ||
559 | #define DINTRE_CUR_UR_EN (1 << 6) | ||
560 | #define DINTRE_STR2_UR_EN (1 << 5) | ||
561 | #define DINTRE_STR1_UR_EN (1 << 4) | ||
562 | #define DINTRE_VEVENT1_EN (1 << 3) | ||
563 | #define DINTRE_VEVENT0_EN (1 << 2) | ||
564 | #define DINTRE_HBLNK1_EN (1 << 1) | ||
565 | #define DINTRE_HBLNK0_EN (1 << 0) | ||
566 | |||
482 | 567 | ||
483 | /* DLSTS - display load status register */ | 568 | /* DLSTS - display load status register */ |
484 | #define DLSTS_RLD_ADONE (1 << 23) | 569 | #define DLSTS_RLD_ADONE (1 << 23) |
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h index a7c63d865aad..063099d48839 100644 --- a/drivers/video/mbx/regs.h +++ b/drivers/video/mbx/regs.h | |||
@@ -30,7 +30,7 @@ | |||
30 | #define VOVRCLK __REG_2700G(0x00000044) | 30 | #define VOVRCLK __REG_2700G(0x00000044) |
31 | #define PIXCLK __REG_2700G(0x00000048) | 31 | #define PIXCLK __REG_2700G(0x00000048) |
32 | #define MEMCLK __REG_2700G(0x0000004c) | 32 | #define MEMCLK __REG_2700G(0x0000004c) |
33 | #define M24CLK __REG_2700G(0x00000054) | 33 | #define M24CLK __REG_2700G(0x00000050) |
34 | #define MBXCLK __REG_2700G(0x00000054) | 34 | #define MBXCLK __REG_2700G(0x00000054) |
35 | #define SDCLK __REG_2700G(0x00000058) | 35 | #define SDCLK __REG_2700G(0x00000058) |
36 | #define PIXCLKDIV __REG_2700G(0x0000005c) | 36 | #define PIXCLKDIV __REG_2700G(0x0000005c) |
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 3741ad729401..42f5d76a8777 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #define DPRINTK(fmt, args...) | 27 | #define DPRINTK(fmt, args...) |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | const char *global_mode_option; | 30 | const char *fb_mode_option; |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * Standard video mode definitions (taken from XFree86) | 33 | * Standard video mode definitions (taken from XFree86) |
@@ -72,7 +72,7 @@ static const struct fb_videomode modedb[] = { | |||
72 | 0, FB_VMODE_NONINTERLACED | 72 | 0, FB_VMODE_NONINTERLACED |
73 | }, { | 73 | }, { |
74 | /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ | 74 | /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ |
75 | NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, | 75 | NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, |
76 | 0, FB_VMODE_INTERLACED | 76 | 0, FB_VMODE_INTERLACED |
77 | }, { | 77 | }, { |
78 | /* 800x600 @ 72 Hz, 48.0 kHz hsync */ | 78 | /* 800x600 @ 72 Hz, 48.0 kHz hsync */ |
@@ -120,11 +120,11 @@ static const struct fb_videomode modedb[] = { | |||
120 | 0, FB_VMODE_NONINTERLACED | 120 | 0, FB_VMODE_NONINTERLACED |
121 | }, { | 121 | }, { |
122 | /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ | 122 | /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ |
123 | NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, | 123 | NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, |
124 | 0, FB_VMODE_NONINTERLACED | 124 | 0, FB_VMODE_NONINTERLACED |
125 | }, { | 125 | }, { |
126 | /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ | 126 | /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ |
127 | NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, | 127 | NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, |
128 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 128 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
129 | }, { | 129 | }, { |
130 | /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ | 130 | /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ |
@@ -253,7 +253,7 @@ static const struct fb_videomode modedb[] = { | |||
253 | FB_VMODE_NONINTERLACED | 253 | FB_VMODE_NONINTERLACED |
254 | }, { | 254 | }, { |
255 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ | 255 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ |
256 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, | 256 | NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, |
257 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 257 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
258 | }, { | 258 | }, { |
259 | /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ | 259 | /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ |
@@ -306,7 +306,7 @@ const struct fb_videomode vesa_modes[] = { | |||
306 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 306 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
307 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | 307 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, |
308 | /* 12 1024x768i-43 VESA */ | 308 | /* 12 1024x768i-43 VESA */ |
309 | { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, | 309 | { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, |
310 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 310 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
311 | FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, | 311 | FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, |
312 | /* 13 1024x768-60 VESA */ | 312 | /* 13 1024x768-60 VESA */ |
@@ -383,7 +383,7 @@ const struct fb_videomode vesa_modes[] = { | |||
383 | { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, | 383 | { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, |
384 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | 384 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, |
385 | /* 33 1920x1440-75 VESA */ | 385 | /* 33 1920x1440-75 VESA */ |
386 | { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, | 386 | { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, |
387 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | 387 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, |
388 | }; | 388 | }; |
389 | EXPORT_SYMBOL(vesa_modes); | 389 | EXPORT_SYMBOL(vesa_modes); |
@@ -510,7 +510,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
510 | default_bpp = 8; | 510 | default_bpp = 8; |
511 | 511 | ||
512 | /* Did the user specify a video mode? */ | 512 | /* Did the user specify a video mode? */ |
513 | if (mode_option || (mode_option = global_mode_option)) { | 513 | if (mode_option || (mode_option = fb_mode_option)) { |
514 | const char *name = mode_option; | 514 | const char *name = mode_option; |
515 | unsigned int namelen = strlen(name); | 515 | unsigned int namelen = strlen(name); |
516 | int res_specified = 0, bpp_specified = 0, refresh_specified = 0; | 516 | int res_specified = 0, bpp_specified = 0, refresh_specified = 0; |
@@ -606,26 +606,43 @@ done: | |||
606 | DPRINTK("Trying specified video mode%s %ix%i\n", | 606 | DPRINTK("Trying specified video mode%s %ix%i\n", |
607 | refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); | 607 | refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); |
608 | 608 | ||
609 | diff = refresh; | 609 | if (!refresh_specified) { |
610 | /* | ||
611 | * If the caller has provided a custom mode database and a | ||
612 | * valid monspecs structure, we look for the mode with the | ||
613 | * highest refresh rate. Otherwise we play it safe it and | ||
614 | * try to find a mode with a refresh rate closest to the | ||
615 | * standard 60 Hz. | ||
616 | */ | ||
617 | if (db != modedb && | ||
618 | info->monspecs.vfmin && info->monspecs.vfmax && | ||
619 | info->monspecs.hfmin && info->monspecs.hfmax && | ||
620 | info->monspecs.dclkmax) { | ||
621 | refresh = 1000; | ||
622 | } else { | ||
623 | refresh = 60; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | diff = -1; | ||
610 | best = -1; | 628 | best = -1; |
611 | for (i = 0; i < dbsize; i++) { | 629 | for (i = 0; i < dbsize; i++) { |
612 | if (name_matches(db[i], name, namelen) || | 630 | if ((name_matches(db[i], name, namelen) || |
613 | (res_specified && res_matches(db[i], xres, yres))) { | 631 | (res_specified && res_matches(db[i], xres, yres))) && |
614 | if(!fb_try_mode(var, info, &db[i], bpp)) { | 632 | !fb_try_mode(var, info, &db[i], bpp)) { |
615 | if(!refresh_specified || db[i].refresh == refresh) | 633 | if (refresh_specified && db[i].refresh == refresh) { |
616 | return 1; | 634 | return 1; |
617 | else { | 635 | } else { |
618 | if(diff > abs(db[i].refresh - refresh)) { | 636 | if (abs(db[i].refresh - refresh) < diff) { |
619 | diff = abs(db[i].refresh - refresh); | 637 | diff = abs(db[i].refresh - refresh); |
620 | best = i; | 638 | best = i; |
621 | } | ||
622 | } | 639 | } |
623 | } | 640 | } |
624 | } | 641 | } |
625 | } | 642 | } |
626 | if (best != -1) { | 643 | if (best != -1) { |
627 | fb_try_mode(var, info, &db[best], bpp); | 644 | fb_try_mode(var, info, &db[best], bpp); |
628 | return 2; | 645 | return (refresh_specified) ? 2 : 1; |
629 | } | 646 | } |
630 | 647 | ||
631 | diff = xres + yres; | 648 | diff = xres + yres; |
@@ -938,6 +955,7 @@ void fb_destroy_modelist(struct list_head *head) | |||
938 | kfree(pos); | 955 | kfree(pos); |
939 | } | 956 | } |
940 | } | 957 | } |
958 | EXPORT_SYMBOL_GPL(fb_destroy_modelist); | ||
941 | 959 | ||
942 | /** | 960 | /** |
943 | * fb_videomode_to_modelist: convert mode array to mode list | 961 | * fb_videomode_to_modelist: convert mode array to mode list |
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 731d7a5c5aa2..4b6a99b5be0d 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c | |||
@@ -72,7 +72,6 @@ | |||
72 | #include <asm/irq.h> | 72 | #include <asm/irq.h> |
73 | #include <asm/pgtable.h> | 73 | #include <asm/pgtable.h> |
74 | #include <asm/system.h> | 74 | #include <asm/system.h> |
75 | #include <asm/uaccess.h> | ||
76 | 75 | ||
77 | #ifdef CONFIG_MTRR | 76 | #ifdef CONFIG_MTRR |
78 | #include <asm/mtrr.h> | 77 | #include <asm/mtrr.h> |
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index afe4567e1ff4..6fd7cb8f9b8e 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c | |||
@@ -125,11 +125,13 @@ void nvidia_create_i2c_busses(struct nvidia_par *par) | |||
125 | par->chan[1].par = par; | 125 | par->chan[1].par = par; |
126 | par->chan[2].par = par; | 126 | par->chan[2].par = par; |
127 | 127 | ||
128 | par->chan[0].ddc_base = 0x36; | 128 | par->chan[0].ddc_base = (par->reverse_i2c) ? 0x36 : 0x3e; |
129 | nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON); | 129 | nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", |
130 | (par->reverse_i2c) ? I2C_CLASS_HWMON : 0); | ||
130 | 131 | ||
131 | par->chan[1].ddc_base = 0x3e; | 132 | par->chan[1].ddc_base = (par->reverse_i2c) ? 0x3e : 0x36; |
132 | nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0); | 133 | nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", |
134 | (par->reverse_i2c) ? 0 : I2C_CLASS_HWMON); | ||
133 | 135 | ||
134 | par->chan[2].ddc_base = 0x50; | 136 | par->chan[2].ddc_base = 0x50; |
135 | nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0); | 137 | nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0); |
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index 2fdf77ec39fc..f132aab8c5de 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h | |||
@@ -135,6 +135,7 @@ struct nvidia_par { | |||
135 | int paneltweak; | 135 | int paneltweak; |
136 | int LVDS; | 136 | int LVDS; |
137 | int pm_state; | 137 | int pm_state; |
138 | int reverse_i2c; | ||
138 | u32 crtcSync_read; | 139 | u32 crtcSync_read; |
139 | u32 fpSyncs; | 140 | u32 fpSyncs; |
140 | u32 dmaPut; | 141 | u32 dmaPut; |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index a7fe214f0f77..30e14eb1f51e 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -79,6 +79,7 @@ static int noscale __devinitdata = 0; | |||
79 | static int paneltweak __devinitdata = 0; | 79 | static int paneltweak __devinitdata = 0; |
80 | static int vram __devinitdata = 0; | 80 | static int vram __devinitdata = 0; |
81 | static int bpp __devinitdata = 8; | 81 | static int bpp __devinitdata = 8; |
82 | static int reverse_i2c __devinitdata; | ||
82 | #ifdef CONFIG_MTRR | 83 | #ifdef CONFIG_MTRR |
83 | static int nomtrr __devinitdata = 0; | 84 | static int nomtrr __devinitdata = 0; |
84 | #endif | 85 | #endif |
@@ -1305,6 +1306,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1305 | par->CRTCnumber = forceCRTC; | 1306 | par->CRTCnumber = forceCRTC; |
1306 | par->FpScale = (!noscale); | 1307 | par->FpScale = (!noscale); |
1307 | par->paneltweak = paneltweak; | 1308 | par->paneltweak = paneltweak; |
1309 | par->reverse_i2c = reverse_i2c; | ||
1308 | 1310 | ||
1309 | /* enable IO and mem if not already done */ | 1311 | /* enable IO and mem if not already done */ |
1310 | pci_read_config_word(pd, PCI_COMMAND, &cmd); | 1312 | pci_read_config_word(pd, PCI_COMMAND, &cmd); |
@@ -1486,6 +1488,8 @@ static int __devinit nvidiafb_setup(char *options) | |||
1486 | noaccel = 1; | 1488 | noaccel = 1; |
1487 | } else if (!strncmp(this_opt, "noscale", 7)) { | 1489 | } else if (!strncmp(this_opt, "noscale", 7)) { |
1488 | noscale = 1; | 1490 | noscale = 1; |
1491 | } else if (!strncmp(this_opt, "reverse_i2c", 11)) { | ||
1492 | reverse_i2c = 1; | ||
1489 | } else if (!strncmp(this_opt, "paneltweak:", 11)) { | 1493 | } else if (!strncmp(this_opt, "paneltweak:", 11)) { |
1490 | paneltweak = simple_strtoul(this_opt+11, NULL, 0); | 1494 | paneltweak = simple_strtoul(this_opt+11, NULL, 0); |
1491 | } else if (!strncmp(this_opt, "vram:", 5)) { | 1495 | } else if (!strncmp(this_opt, "vram:", 5)) { |
@@ -1582,6 +1586,8 @@ MODULE_PARM_DESC(mode_option, "Specify initial video mode"); | |||
1582 | module_param(bpp, int, 0); | 1586 | module_param(bpp, int, 0); |
1583 | MODULE_PARM_DESC(bpp, "pixel width in bits" | 1587 | MODULE_PARM_DESC(bpp, "pixel width in bits" |
1584 | "(default=8)"); | 1588 | "(default=8)"); |
1589 | module_param(reverse_i2c, int, 0); | ||
1590 | MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus"); | ||
1585 | #ifdef CONFIG_MTRR | 1591 | #ifdef CONFIG_MTRR |
1586 | module_param(nomtrr, bool, 0); | 1592 | module_param(nomtrr, bool, 0); |
1587 | MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " | 1593 | MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " |
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 10c0cc6e93fc..5591dfb22b18 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * and additional input from James Simmon's port of Hannu Mallat's tdfx | 11 | * and additional input from James Simmon's port of Hannu Mallat's tdfx |
12 | * driver. | 12 | * driver. |
13 | * | 13 | * |
14 | * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I | 14 | * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I |
15 | * have no access to other pm2fb implementations. Sparc (and thus | 15 | * have no access to other pm2fb implementations. Sparc (and thus |
16 | * hopefully other big-endian) devices now work, thanks to a lot of | 16 | * hopefully other big-endian) devices now work, thanks to a lot of |
17 | * testing work by Ron Murray. I have no access to CVision hardware, | 17 | * testing work by Ron Murray. I have no access to CVision hardware, |
@@ -38,6 +38,9 @@ | |||
38 | #include <linux/fb.h> | 38 | #include <linux/fb.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
41 | #ifdef CONFIG_MTRR | ||
42 | #include <asm/mtrr.h> | ||
43 | #endif | ||
41 | 44 | ||
42 | #include <video/permedia2.h> | 45 | #include <video/permedia2.h> |
43 | #include <video/cvisionppc.h> | 46 | #include <video/cvisionppc.h> |
@@ -52,15 +55,19 @@ | |||
52 | 55 | ||
53 | #undef PM2FB_MASTER_DEBUG | 56 | #undef PM2FB_MASTER_DEBUG |
54 | #ifdef PM2FB_MASTER_DEBUG | 57 | #ifdef PM2FB_MASTER_DEBUG |
55 | #define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) | 58 | #define DPRINTK(a, b...) \ |
59 | printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) | ||
56 | #else | 60 | #else |
57 | #define DPRINTK(a,b...) | 61 | #define DPRINTK(a, b...) |
58 | #endif | 62 | #endif |
59 | 63 | ||
64 | #define PM2_PIXMAP_SIZE (1600 * 4) | ||
65 | |||
60 | /* | 66 | /* |
61 | * Driver data | 67 | * Driver data |
62 | */ | 68 | */ |
63 | static char *mode __devinitdata = NULL; | 69 | static int hwcursor = 1; |
70 | static char *mode __devinitdata; | ||
64 | 71 | ||
65 | /* | 72 | /* |
66 | * The XFree GLINT driver will (I think to implement hardware cursor | 73 | * The XFree GLINT driver will (I think to implement hardware cursor |
@@ -73,6 +80,11 @@ static char *mode __devinitdata = NULL; | |||
73 | */ | 80 | */ |
74 | static int lowhsync; | 81 | static int lowhsync; |
75 | static int lowvsync; | 82 | static int lowvsync; |
83 | static int noaccel __devinitdata; | ||
84 | /* mtrr option */ | ||
85 | #ifdef CONFIG_MTRR | ||
86 | static int nomtrr __devinitdata; | ||
87 | #endif | ||
76 | 88 | ||
77 | /* | 89 | /* |
78 | * The hardware state of the graphics card that isn't part of the | 90 | * The hardware state of the graphics card that isn't part of the |
@@ -88,6 +100,7 @@ struct pm2fb_par | |||
88 | u32 mem_control; /* MemControl reg at probe */ | 100 | u32 mem_control; /* MemControl reg at probe */ |
89 | u32 boot_address; /* BootAddress reg at probe */ | 101 | u32 boot_address; /* BootAddress reg at probe */ |
90 | u32 palette[16]; | 102 | u32 palette[16]; |
103 | int mtrr_handle; | ||
91 | }; | 104 | }; |
92 | 105 | ||
93 | /* | 106 | /* |
@@ -135,60 +148,39 @@ static struct fb_var_screeninfo pm2fb_var __devinitdata = { | |||
135 | * Utility functions | 148 | * Utility functions |
136 | */ | 149 | */ |
137 | 150 | ||
138 | static inline u32 RD32(unsigned char __iomem *base, s32 off) | 151 | static inline u32 pm2_RD(struct pm2fb_par *p, s32 off) |
139 | { | ||
140 | return fb_readl(base + off); | ||
141 | } | ||
142 | |||
143 | static inline void WR32(unsigned char __iomem *base, s32 off, u32 v) | ||
144 | { | 152 | { |
145 | fb_writel(v, base + off); | 153 | return fb_readl(p->v_regs + off); |
146 | } | 154 | } |
147 | 155 | ||
148 | static inline u32 pm2_RD(struct pm2fb_par* p, s32 off) | 156 | static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v) |
149 | { | 157 | { |
150 | return RD32(p->v_regs, off); | 158 | fb_writel(v, p->v_regs + off); |
151 | } | 159 | } |
152 | 160 | ||
153 | static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) | 161 | static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx) |
154 | { | 162 | { |
155 | WR32(p->v_regs, off, v); | 163 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); |
164 | mb(); | ||
165 | return pm2_RD(p, PM2R_RD_INDEXED_DATA); | ||
156 | } | 166 | } |
157 | 167 | ||
158 | static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) | 168 | static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx) |
159 | { | 169 | { |
160 | int index = PM2R_RD_INDEXED_DATA; | 170 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
161 | switch (p->type) { | ||
162 | case PM2_TYPE_PERMEDIA2: | ||
163 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); | ||
164 | break; | ||
165 | case PM2_TYPE_PERMEDIA2V: | ||
166 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | ||
167 | index = PM2VR_RD_INDEXED_DATA; | ||
168 | break; | ||
169 | } | ||
170 | mb(); | 171 | mb(); |
171 | return pm2_RD(p, index); | 172 | return pm2_RD(p, PM2VR_RD_INDEXED_DATA); |
172 | } | 173 | } |
173 | 174 | ||
174 | static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | 175 | static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) |
175 | { | 176 | { |
176 | int index = PM2R_RD_INDEXED_DATA; | 177 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); |
177 | switch (p->type) { | ||
178 | case PM2_TYPE_PERMEDIA2: | ||
179 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); | ||
180 | break; | ||
181 | case PM2_TYPE_PERMEDIA2V: | ||
182 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | ||
183 | index = PM2VR_RD_INDEXED_DATA; | ||
184 | break; | ||
185 | } | ||
186 | wmb(); | 178 | wmb(); |
187 | pm2_WR(p, index, v); | 179 | pm2_WR(p, PM2R_RD_INDEXED_DATA, v); |
188 | wmb(); | 180 | wmb(); |
189 | } | 181 | } |
190 | 182 | ||
191 | static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | 183 | static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) |
192 | { | 184 | { |
193 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 185 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
194 | wmb(); | 186 | wmb(); |
@@ -199,10 +191,10 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | |||
199 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT | 191 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT |
200 | #define WAIT_FIFO(p, a) | 192 | #define WAIT_FIFO(p, a) |
201 | #else | 193 | #else |
202 | static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | 194 | static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a) |
203 | { | 195 | { |
204 | while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); | 196 | while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a) |
205 | mb(); | 197 | cpu_relax(); |
206 | } | 198 | } |
207 | #endif | 199 | #endif |
208 | 200 | ||
@@ -238,7 +230,7 @@ static u32 partprod(u32 xres) | |||
238 | 230 | ||
239 | for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) | 231 | for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) |
240 | ; | 232 | ; |
241 | if ( pp_table[i].width == 0 ) | 233 | if (pp_table[i].width == 0) |
242 | DPRINTK("invalid width %u\n", xres); | 234 | DPRINTK("invalid width %u\n", xres); |
243 | return pp_table[i].pp; | 235 | return pp_table[i].pp; |
244 | } | 236 | } |
@@ -246,25 +238,22 @@ static u32 partprod(u32 xres) | |||
246 | static u32 to3264(u32 timing, int bpp, int is64) | 238 | static u32 to3264(u32 timing, int bpp, int is64) |
247 | { | 239 | { |
248 | switch (bpp) { | 240 | switch (bpp) { |
241 | case 24: | ||
242 | timing *= 3; | ||
249 | case 8: | 243 | case 8: |
250 | timing >>= 2 + is64; | 244 | timing >>= 1; |
251 | break; | ||
252 | case 16: | 245 | case 16: |
253 | timing >>= 1 + is64; | 246 | timing >>= 1; |
254 | break; | ||
255 | case 24: | ||
256 | timing = (timing * 3) >> (2 + is64); | ||
257 | break; | ||
258 | case 32: | 247 | case 32: |
259 | if (is64) | ||
260 | timing >>= 1; | ||
261 | break; | 248 | break; |
262 | } | 249 | } |
250 | if (is64) | ||
251 | timing >>= 1; | ||
263 | return timing; | 252 | return timing; |
264 | } | 253 | } |
265 | 254 | ||
266 | static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, | 255 | static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn, |
267 | unsigned char* pp) | 256 | unsigned char *pp) |
268 | { | 257 | { |
269 | unsigned char m; | 258 | unsigned char m; |
270 | unsigned char n; | 259 | unsigned char n; |
@@ -278,13 +267,13 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, | |||
278 | for (m = 2; m; m++) { | 267 | for (m = 2; m; m++) { |
279 | f = PM2_REFERENCE_CLOCK * m / n; | 268 | f = PM2_REFERENCE_CLOCK * m / n; |
280 | if (f >= 150000 && f <= 300000) { | 269 | if (f >= 150000 && f <= 300000) { |
281 | for ( p = 0; p < 5; p++, f >>= 1) { | 270 | for (p = 0; p < 5; p++, f >>= 1) { |
282 | curr = ( clk > f ) ? clk - f : f - clk; | 271 | curr = (clk > f) ? clk - f : f - clk; |
283 | if ( curr < delta ) { | 272 | if (curr < delta) { |
284 | delta=curr; | 273 | delta = curr; |
285 | *mm=m; | 274 | *mm = m; |
286 | *nn=n; | 275 | *nn = n; |
287 | *pp=p; | 276 | *pp = p; |
288 | } | 277 | } |
289 | } | 278 | } |
290 | } | 279 | } |
@@ -292,8 +281,8 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, | |||
292 | } | 281 | } |
293 | } | 282 | } |
294 | 283 | ||
295 | static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, | 284 | static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn, |
296 | unsigned char* pp) | 285 | unsigned char *pp) |
297 | { | 286 | { |
298 | unsigned char m; | 287 | unsigned char m; |
299 | unsigned char n; | 288 | unsigned char n; |
@@ -302,23 +291,24 @@ static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, | |||
302 | s32 delta = 1000; | 291 | s32 delta = 1000; |
303 | 292 | ||
304 | *mm = *nn = *pp = 0; | 293 | *mm = *nn = *pp = 0; |
305 | for ( m = 1; m < 128; m++) { | 294 | for (m = 1; m < 128; m++) { |
306 | for (n = 2 * m + 1; n; n++) { | 295 | for (n = 2 * m + 1; n; n++) { |
307 | for ( p = 0; p < 2; p++) { | 296 | for (p = 0; p < 2; p++) { |
308 | f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m; | 297 | f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m; |
309 | if ( clk > f - delta && clk < f + delta ) { | 298 | if (clk > f - delta && clk < f + delta) { |
310 | delta = ( clk > f ) ? clk - f : f - clk; | 299 | delta = (clk > f) ? clk - f : f - clk; |
311 | *mm=m; | 300 | *mm = m; |
312 | *nn=n; | 301 | *nn = n; |
313 | *pp=p; | 302 | *pp = p; |
314 | } | 303 | } |
315 | } | 304 | } |
316 | } | 305 | } |
317 | } | 306 | } |
318 | } | 307 | } |
319 | 308 | ||
320 | static void clear_palette(struct pm2fb_par* p) { | 309 | static void clear_palette(struct pm2fb_par *p) |
321 | int i=256; | 310 | { |
311 | int i = 256; | ||
322 | 312 | ||
323 | WAIT_FIFO(p, 1); | 313 | WAIT_FIFO(p, 1); |
324 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); | 314 | pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); |
@@ -331,14 +321,14 @@ static void clear_palette(struct pm2fb_par* p) { | |||
331 | } | 321 | } |
332 | } | 322 | } |
333 | 323 | ||
334 | static void reset_card(struct pm2fb_par* p) | 324 | static void reset_card(struct pm2fb_par *p) |
335 | { | 325 | { |
336 | if (p->type == PM2_TYPE_PERMEDIA2V) | 326 | if (p->type == PM2_TYPE_PERMEDIA2V) |
337 | pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); | 327 | pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); |
338 | pm2_WR(p, PM2R_RESET_STATUS, 0); | 328 | pm2_WR(p, PM2R_RESET_STATUS, 0); |
339 | mb(); | 329 | mb(); |
340 | while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) | 330 | while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) |
341 | ; | 331 | cpu_relax(); |
342 | mb(); | 332 | mb(); |
343 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT | 333 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT |
344 | DPRINTK("FIFO disconnect enabled\n"); | 334 | DPRINTK("FIFO disconnect enabled\n"); |
@@ -354,11 +344,11 @@ static void reset_card(struct pm2fb_par* p) | |||
354 | pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); | 344 | pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); |
355 | } | 345 | } |
356 | 346 | ||
357 | static void reset_config(struct pm2fb_par* p) | 347 | static void reset_config(struct pm2fb_par *p) |
358 | { | 348 | { |
359 | WAIT_FIFO(p, 52); | 349 | WAIT_FIFO(p, 53); |
360 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & | 350 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & |
361 | ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); | 351 | ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED)); |
362 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); | 352 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); |
363 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); | 353 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); |
364 | pm2_WR(p, PM2R_FIFO_CONTROL, 0); | 354 | pm2_WR(p, PM2R_FIFO_CONTROL, 0); |
@@ -393,31 +383,32 @@ static void reset_config(struct pm2fb_par* p) | |||
393 | pm2_WR(p, PM2R_STATISTICS_MODE, 0); | 383 | pm2_WR(p, PM2R_STATISTICS_MODE, 0); |
394 | pm2_WR(p, PM2R_SCISSOR_MODE, 0); | 384 | pm2_WR(p, PM2R_SCISSOR_MODE, 0); |
395 | pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); | 385 | pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); |
386 | pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff); | ||
396 | switch (p->type) { | 387 | switch (p->type) { |
397 | case PM2_TYPE_PERMEDIA2: | 388 | case PM2_TYPE_PERMEDIA2: |
398 | pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ | 389 | pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ |
399 | pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); | 390 | pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); |
400 | pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); | 391 | pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); |
392 | pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); | ||
393 | pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); | ||
394 | pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); | ||
395 | pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); | ||
396 | pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); | ||
401 | break; | 397 | break; |
402 | case PM2_TYPE_PERMEDIA2V: | 398 | case PM2_TYPE_PERMEDIA2V: |
403 | pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ | 399 | pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ |
404 | break; | 400 | break; |
405 | } | 401 | } |
406 | pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); | ||
407 | pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); | ||
408 | pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); | ||
409 | pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); | ||
410 | pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); | ||
411 | } | 402 | } |
412 | 403 | ||
413 | static void set_aperture(struct pm2fb_par* p, u32 depth) | 404 | static void set_aperture(struct pm2fb_par *p, u32 depth) |
414 | { | 405 | { |
415 | /* | 406 | /* |
416 | * The hardware is little-endian. When used in big-endian | 407 | * The hardware is little-endian. When used in big-endian |
417 | * hosts, the on-chip aperture settings are used where | 408 | * hosts, the on-chip aperture settings are used where |
418 | * possible to translate from host to card byte order. | 409 | * possible to translate from host to card byte order. |
419 | */ | 410 | */ |
420 | WAIT_FIFO(p, 4); | 411 | WAIT_FIFO(p, 2); |
421 | #ifdef __LITTLE_ENDIAN | 412 | #ifdef __LITTLE_ENDIAN |
422 | pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); | 413 | pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); |
423 | #else | 414 | #else |
@@ -440,11 +431,11 @@ static void set_aperture(struct pm2fb_par* p, u32 depth) | |||
440 | } | 431 | } |
441 | #endif | 432 | #endif |
442 | 433 | ||
443 | // We don't use aperture two, so this may be superflous | 434 | /* We don't use aperture two, so this may be superflous */ |
444 | pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); | 435 | pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); |
445 | } | 436 | } |
446 | 437 | ||
447 | static void set_color(struct pm2fb_par* p, unsigned char regno, | 438 | static void set_color(struct pm2fb_par *p, unsigned char regno, |
448 | unsigned char r, unsigned char g, unsigned char b) | 439 | unsigned char r, unsigned char g, unsigned char b) |
449 | { | 440 | { |
450 | WAIT_FIFO(p, 4); | 441 | WAIT_FIFO(p, 4); |
@@ -457,7 +448,7 @@ static void set_color(struct pm2fb_par* p, unsigned char regno, | |||
457 | pm2_WR(p, PM2R_RD_PALETTE_DATA, b); | 448 | pm2_WR(p, PM2R_RD_PALETTE_DATA, b); |
458 | } | 449 | } |
459 | 450 | ||
460 | static void set_memclock(struct pm2fb_par* par, u32 clk) | 451 | static void set_memclock(struct pm2fb_par *par, u32 clk) |
461 | { | 452 | { |
462 | int i; | 453 | int i; |
463 | unsigned char m, n, p; | 454 | unsigned char m, n, p; |
@@ -465,7 +456,7 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) | |||
465 | switch (par->type) { | 456 | switch (par->type) { |
466 | case PM2_TYPE_PERMEDIA2V: | 457 | case PM2_TYPE_PERMEDIA2V: |
467 | pm2v_mnp(clk/2, &m, &n, &p); | 458 | pm2v_mnp(clk/2, &m, &n, &p); |
468 | WAIT_FIFO(par, 8); | 459 | WAIT_FIFO(par, 12); |
469 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); | 460 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); |
470 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); | 461 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); |
471 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); | 462 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); |
@@ -473,10 +464,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) | |||
473 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); | 464 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); |
474 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); | 465 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); |
475 | rmb(); | 466 | rmb(); |
476 | for (i = 256; | 467 | for (i = 256; i; i--) |
477 | i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2); | 468 | if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2) |
478 | i--) | 469 | break; |
479 | ; | ||
480 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); | 470 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); |
481 | break; | 471 | break; |
482 | case PM2_TYPE_PERMEDIA2: | 472 | case PM2_TYPE_PERMEDIA2: |
@@ -488,15 +478,14 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) | |||
488 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); | 478 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); |
489 | pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); | 479 | pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); |
490 | rmb(); | 480 | rmb(); |
491 | for (i = 256; | 481 | for (i = 256; i; i--) |
492 | i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); | 482 | if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) |
493 | i--) | 483 | break; |
494 | ; | ||
495 | break; | 484 | break; |
496 | } | 485 | } |
497 | } | 486 | } |
498 | 487 | ||
499 | static void set_pixclock(struct pm2fb_par* par, u32 clk) | 488 | static void set_pixclock(struct pm2fb_par *par, u32 clk) |
500 | { | 489 | { |
501 | int i; | 490 | int i; |
502 | unsigned char m, n, p; | 491 | unsigned char m, n, p; |
@@ -504,17 +493,16 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk) | |||
504 | switch (par->type) { | 493 | switch (par->type) { |
505 | case PM2_TYPE_PERMEDIA2: | 494 | case PM2_TYPE_PERMEDIA2: |
506 | pm2_mnp(clk, &m, &n, &p); | 495 | pm2_mnp(clk, &m, &n, &p); |
507 | WAIT_FIFO(par, 8); | 496 | WAIT_FIFO(par, 10); |
508 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); | 497 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); |
509 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); | 498 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); |
510 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); | 499 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); |
511 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); | 500 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); |
512 | pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); | 501 | pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); |
513 | rmb(); | 502 | rmb(); |
514 | for (i = 256; | 503 | for (i = 256; i; i--) |
515 | i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); | 504 | if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) |
516 | i--) | 505 | break; |
517 | ; | ||
518 | break; | 506 | break; |
519 | case PM2_TYPE_PERMEDIA2V: | 507 | case PM2_TYPE_PERMEDIA2V: |
520 | pm2v_mnp(clk/2, &m, &n, &p); | 508 | pm2v_mnp(clk/2, &m, &n, &p); |
@@ -528,11 +516,10 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk) | |||
528 | } | 516 | } |
529 | } | 517 | } |
530 | 518 | ||
531 | static void set_video(struct pm2fb_par* p, u32 video) { | 519 | static void set_video(struct pm2fb_par *p, u32 video) |
520 | { | ||
532 | u32 tmp; | 521 | u32 tmp; |
533 | u32 vsync; | 522 | u32 vsync = video; |
534 | |||
535 | vsync = video; | ||
536 | 523 | ||
537 | DPRINTK("video = 0x%x\n", video); | 524 | DPRINTK("video = 0x%x\n", video); |
538 | 525 | ||
@@ -542,10 +529,10 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
542 | * driver may well. So always set +hsync/+vsync and then set | 529 | * driver may well. So always set +hsync/+vsync and then set |
543 | * the RAMDAC to invert the sync if necessary. | 530 | * the RAMDAC to invert the sync if necessary. |
544 | */ | 531 | */ |
545 | vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK); | 532 | vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK); |
546 | vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH; | 533 | vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH; |
547 | 534 | ||
548 | WAIT_FIFO(p, 5); | 535 | WAIT_FIFO(p, 3); |
549 | pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); | 536 | pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); |
550 | 537 | ||
551 | switch (p->type) { | 538 | switch (p->type) { |
@@ -564,16 +551,11 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
564 | if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) | 551 | if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) |
565 | tmp |= 4; /* invert vsync */ | 552 | tmp |= 4; /* invert vsync */ |
566 | pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); | 553 | pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); |
567 | pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); | ||
568 | break; | 554 | break; |
569 | } | 555 | } |
570 | } | 556 | } |
571 | 557 | ||
572 | /* | 558 | /* |
573 | * | ||
574 | */ | ||
575 | |||
576 | /** | ||
577 | * pm2fb_check_var - Optional function. Validates a var passed in. | 559 | * pm2fb_check_var - Optional function. Validates a var passed in. |
578 | * @var: frame buffer variable screen structure | 560 | * @var: frame buffer variable screen structure |
579 | * @info: frame buffer structure that represents a single frame buffer | 561 | * @info: frame buffer structure that represents a single frame buffer |
@@ -594,15 +576,22 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
594 | } | 576 | } |
595 | 577 | ||
596 | if (var->xres != var->xres_virtual) { | 578 | if (var->xres != var->xres_virtual) { |
597 | DPRINTK("virtual x resolution != physical x resolution not supported\n"); | 579 | DPRINTK("virtual x resolution != " |
580 | "physical x resolution not supported\n"); | ||
598 | return -EINVAL; | 581 | return -EINVAL; |
599 | } | 582 | } |
600 | 583 | ||
601 | if (var->yres > var->yres_virtual) { | 584 | if (var->yres > var->yres_virtual) { |
602 | DPRINTK("virtual y resolution < physical y resolution not possible\n"); | 585 | DPRINTK("virtual y resolution < " |
586 | "physical y resolution not possible\n"); | ||
603 | return -EINVAL; | 587 | return -EINVAL; |
604 | } | 588 | } |
605 | 589 | ||
590 | /* permedia cannot blit over 2048 */ | ||
591 | if (var->yres_virtual > 2047) { | ||
592 | var->yres_virtual = 2047; | ||
593 | } | ||
594 | |||
606 | if (var->xoffset) { | 595 | if (var->xoffset) { |
607 | DPRINTK("xoffset not supported\n"); | 596 | DPRINTK("xoffset not supported\n"); |
608 | return -EINVAL; | 597 | return -EINVAL; |
@@ -614,7 +603,7 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
614 | } | 603 | } |
615 | 604 | ||
616 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ | 605 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ |
617 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); | 606 | lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); |
618 | 607 | ||
619 | if (var->xres < 320 || var->xres > 1600) { | 608 | if (var->xres < 320 || var->xres > 1600) { |
620 | DPRINTK("width not supported: %u\n", var->xres); | 609 | DPRINTK("width not supported: %u\n", var->xres); |
@@ -633,15 +622,18 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
633 | } | 622 | } |
634 | 623 | ||
635 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { | 624 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { |
636 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); | 625 | DPRINTK("pixclock too high (%ldKHz)\n", |
626 | PICOS2KHZ(var->pixclock)); | ||
637 | return -EINVAL; | 627 | return -EINVAL; |
638 | } | 628 | } |
639 | 629 | ||
640 | var->transp.offset = 0; | 630 | var->transp.offset = 0; |
641 | var->transp.length = 0; | 631 | var->transp.length = 0; |
642 | switch(var->bits_per_pixel) { | 632 | switch (var->bits_per_pixel) { |
643 | case 8: | 633 | case 8: |
644 | var->red.length = var->green.length = var->blue.length = 8; | 634 | var->red.length = 8; |
635 | var->green.length = 8; | ||
636 | var->blue.length = 8; | ||
645 | break; | 637 | break; |
646 | case 16: | 638 | case 16: |
647 | var->red.offset = 11; | 639 | var->red.offset = 11; |
@@ -657,7 +649,9 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
657 | var->red.offset = 16; | 649 | var->red.offset = 16; |
658 | var->green.offset = 8; | 650 | var->green.offset = 8; |
659 | var->blue.offset = 0; | 651 | var->blue.offset = 0; |
660 | var->red.length = var->green.length = var->blue.length = 8; | 652 | var->red.length = 8; |
653 | var->green.length = 8; | ||
654 | var->blue.length = 8; | ||
661 | break; | 655 | break; |
662 | case 24: | 656 | case 24: |
663 | #ifdef __BIG_ENDIAN | 657 | #ifdef __BIG_ENDIAN |
@@ -668,10 +662,13 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
668 | var->blue.offset = 0; | 662 | var->blue.offset = 0; |
669 | #endif | 663 | #endif |
670 | var->green.offset = 8; | 664 | var->green.offset = 8; |
671 | var->red.length = var->green.length = var->blue.length = 8; | 665 | var->red.length = 8; |
666 | var->green.length = 8; | ||
667 | var->blue.length = 8; | ||
672 | break; | 668 | break; |
673 | } | 669 | } |
674 | var->height = var->width = -1; | 670 | var->height = -1; |
671 | var->width = -1; | ||
675 | 672 | ||
676 | var->accel_flags = 0; /* Can't mmap if this is on */ | 673 | var->accel_flags = 0; /* Can't mmap if this is on */ |
677 | 674 | ||
@@ -691,7 +688,9 @@ static int pm2fb_set_par(struct fb_info *info) | |||
691 | { | 688 | { |
692 | struct pm2fb_par *par = info->par; | 689 | struct pm2fb_par *par = info->par; |
693 | u32 pixclock; | 690 | u32 pixclock; |
694 | u32 width, height, depth; | 691 | u32 width = (info->var.xres_virtual + 7) & ~7; |
692 | u32 height = info->var.yres_virtual; | ||
693 | u32 depth = (info->var.bits_per_pixel + 7) & ~7; | ||
695 | u32 hsstart, hsend, hbend, htotal; | 694 | u32 hsstart, hsend, hbend, htotal; |
696 | u32 vsstart, vsend, vbend, vtotal; | 695 | u32 vsstart, vsend, vbend, vtotal; |
697 | u32 stride; | 696 | u32 stride; |
@@ -701,22 +700,19 @@ static int pm2fb_set_par(struct fb_info *info) | |||
701 | u32 txtmap = 0; | 700 | u32 txtmap = 0; |
702 | u32 pixsize = 0; | 701 | u32 pixsize = 0; |
703 | u32 clrformat = 0; | 702 | u32 clrformat = 0; |
704 | u32 xres; | 703 | u32 misc = 1; /* 8-bit DAC */ |
704 | u32 xres = (info->var.xres + 31) & ~31; | ||
705 | int data64; | 705 | int data64; |
706 | 706 | ||
707 | reset_card(par); | 707 | reset_card(par); |
708 | reset_config(par); | 708 | reset_config(par); |
709 | clear_palette(par); | 709 | clear_palette(par); |
710 | if ( par->memclock ) | 710 | if (par->memclock) |
711 | set_memclock(par, par->memclock); | 711 | set_memclock(par, par->memclock); |
712 | 712 | ||
713 | width = (info->var.xres_virtual + 7) & ~7; | ||
714 | height = info->var.yres_virtual; | ||
715 | depth = (info->var.bits_per_pixel + 7) & ~7; | ||
716 | depth = (depth > 32) ? 32 : depth; | 713 | depth = (depth > 32) ? 32 : depth; |
717 | data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; | 714 | data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; |
718 | 715 | ||
719 | xres = (info->var.xres + 31) & ~31; | ||
720 | pixclock = PICOS2KHZ(info->var.pixclock); | 716 | pixclock = PICOS2KHZ(info->var.pixclock); |
721 | if (pixclock > PM2_MAX_PIXCLOCK) { | 717 | if (pixclock > PM2_MAX_PIXCLOCK) { |
722 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); | 718 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); |
@@ -731,7 +727,8 @@ static int pm2fb_set_par(struct fb_info *info) | |||
731 | ? info->var.lower_margin - 1 | 727 | ? info->var.lower_margin - 1 |
732 | : 0; /* FIXME! */ | 728 | : 0; /* FIXME! */ |
733 | vsend = info->var.lower_margin + info->var.vsync_len - 1; | 729 | vsend = info->var.lower_margin + info->var.vsync_len - 1; |
734 | vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin; | 730 | vbend = info->var.lower_margin + info->var.vsync_len + |
731 | info->var.upper_margin; | ||
735 | vtotal = info->var.yres + vbend - 1; | 732 | vtotal = info->var.yres + vbend - 1; |
736 | stride = to3264(width, depth, 1); | 733 | stride = to3264(width, depth, 1); |
737 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); | 734 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); |
@@ -744,25 +741,25 @@ static int pm2fb_set_par(struct fb_info *info) | |||
744 | video |= PM2F_HSYNC_ACT_LOW; | 741 | video |= PM2F_HSYNC_ACT_LOW; |
745 | } else | 742 | } else |
746 | video |= PM2F_HSYNC_ACT_HIGH; | 743 | video |= PM2F_HSYNC_ACT_HIGH; |
747 | } | 744 | } else |
748 | else | ||
749 | video |= PM2F_HSYNC_ACT_LOW; | 745 | video |= PM2F_HSYNC_ACT_LOW; |
746 | |||
750 | if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { | 747 | if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { |
751 | if (lowvsync) { | 748 | if (lowvsync) { |
752 | DPRINTK("ignoring +vsync, using -vsync.\n"); | 749 | DPRINTK("ignoring +vsync, using -vsync.\n"); |
753 | video |= PM2F_VSYNC_ACT_LOW; | 750 | video |= PM2F_VSYNC_ACT_LOW; |
754 | } else | 751 | } else |
755 | video |= PM2F_VSYNC_ACT_HIGH; | 752 | video |= PM2F_VSYNC_ACT_HIGH; |
756 | } | 753 | } else |
757 | else | ||
758 | video |= PM2F_VSYNC_ACT_LOW; | 754 | video |= PM2F_VSYNC_ACT_LOW; |
759 | if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { | 755 | |
756 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { | ||
760 | DPRINTK("interlaced not supported\n"); | 757 | DPRINTK("interlaced not supported\n"); |
761 | return -EINVAL; | 758 | return -EINVAL; |
762 | } | 759 | } |
763 | if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) | 760 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) |
764 | video |= PM2F_LINE_DOUBLE; | 761 | video |= PM2F_LINE_DOUBLE; |
765 | if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW) | 762 | if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) |
766 | video |= PM2F_VIDEO_ENABLE; | 763 | video |= PM2F_VIDEO_ENABLE; |
767 | par->video = video; | 764 | par->video = video; |
768 | 765 | ||
@@ -783,12 +780,10 @@ static int pm2fb_set_par(struct fb_info *info) | |||
783 | 780 | ||
784 | mb(); | 781 | mb(); |
785 | WAIT_FIFO(par, 19); | 782 | WAIT_FIFO(par, 19); |
786 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, | ||
787 | ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF); | ||
788 | switch (depth) { | 783 | switch (depth) { |
789 | case 8: | 784 | case 8: |
790 | pm2_WR(par, PM2R_FB_READ_PIXEL, 0); | 785 | pm2_WR(par, PM2R_FB_READ_PIXEL, 0); |
791 | clrformat = 0x0e; | 786 | clrformat = 0x2e; |
792 | break; | 787 | break; |
793 | case 16: | 788 | case 16: |
794 | pm2_WR(par, PM2R_FB_READ_PIXEL, 1); | 789 | pm2_WR(par, PM2R_FB_READ_PIXEL, 1); |
@@ -796,6 +791,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
796 | txtmap = PM2F_TEXTEL_SIZE_16; | 791 | txtmap = PM2F_TEXTEL_SIZE_16; |
797 | pixsize = 1; | 792 | pixsize = 1; |
798 | clrformat = 0x70; | 793 | clrformat = 0x70; |
794 | misc |= 8; | ||
799 | break; | 795 | break; |
800 | case 32: | 796 | case 32: |
801 | pm2_WR(par, PM2R_FB_READ_PIXEL, 2); | 797 | pm2_WR(par, PM2R_FB_READ_PIXEL, 2); |
@@ -803,6 +799,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
803 | txtmap = PM2F_TEXTEL_SIZE_32; | 799 | txtmap = PM2F_TEXTEL_SIZE_32; |
804 | pixsize = 2; | 800 | pixsize = 2; |
805 | clrformat = 0x20; | 801 | clrformat = 0x20; |
802 | misc |= 8; | ||
806 | break; | 803 | break; |
807 | case 24: | 804 | case 24: |
808 | pm2_WR(par, PM2R_FB_READ_PIXEL, 4); | 805 | pm2_WR(par, PM2R_FB_READ_PIXEL, 4); |
@@ -810,6 +807,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
810 | txtmap = PM2F_TEXTEL_SIZE_24; | 807 | txtmap = PM2F_TEXTEL_SIZE_24; |
811 | pixsize = 4; | 808 | pixsize = 4; |
812 | clrformat = 0x20; | 809 | clrformat = 0x20; |
810 | misc |= 8; | ||
813 | break; | 811 | break; |
814 | } | 812 | } |
815 | pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); | 813 | pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); |
@@ -834,14 +832,19 @@ static int pm2fb_set_par(struct fb_info *info) | |||
834 | pm2_WR(par, PM2R_SCREEN_BASE, base); | 832 | pm2_WR(par, PM2R_SCREEN_BASE, base); |
835 | wmb(); | 833 | wmb(); |
836 | set_video(par, video); | 834 | set_video(par, video); |
837 | WAIT_FIFO(par, 4); | 835 | WAIT_FIFO(par, 10); |
838 | switch (par->type) { | 836 | switch (par->type) { |
839 | case PM2_TYPE_PERMEDIA2: | 837 | case PM2_TYPE_PERMEDIA2: |
840 | pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); | 838 | pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); |
839 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, | ||
840 | (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF); | ||
841 | break; | 841 | break; |
842 | case PM2_TYPE_PERMEDIA2V: | 842 | case PM2_TYPE_PERMEDIA2V: |
843 | pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0); | ||
843 | pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); | 844 | pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); |
844 | pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); | 845 | pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); |
846 | pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc); | ||
847 | pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0); | ||
845 | break; | 848 | break; |
846 | } | 849 | } |
847 | set_pixclock(par, pixclock); | 850 | set_pixclock(par, pixclock); |
@@ -872,16 +875,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
872 | struct pm2fb_par *par = info->par; | 875 | struct pm2fb_par *par = info->par; |
873 | 876 | ||
874 | if (regno >= info->cmap.len) /* no. of hw registers */ | 877 | if (regno >= info->cmap.len) /* no. of hw registers */ |
875 | return 1; | 878 | return -EINVAL; |
876 | /* | 879 | /* |
877 | * Program hardware... do anything you want with transp | 880 | * Program hardware... do anything you want with transp |
878 | */ | 881 | */ |
879 | 882 | ||
880 | /* grayscale works only partially under directcolor */ | 883 | /* grayscale works only partially under directcolor */ |
881 | if (info->var.grayscale) { | 884 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ |
882 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | 885 | if (info->var.grayscale) |
883 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | 886 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; |
884 | } | ||
885 | 887 | ||
886 | /* Directcolor: | 888 | /* Directcolor: |
887 | * var->{color}.offset contains start of bitfield | 889 | * var->{color}.offset contains start of bitfield |
@@ -931,7 +933,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
931 | u32 v; | 933 | u32 v; |
932 | 934 | ||
933 | if (regno >= 16) | 935 | if (regno >= 16) |
934 | return 1; | 936 | return -EINVAL; |
935 | 937 | ||
936 | v = (red << info->var.red.offset) | | 938 | v = (red << info->var.red.offset) | |
937 | (green << info->var.green.offset) | | 939 | (green << info->var.green.offset) | |
@@ -948,8 +950,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
948 | break; | 950 | break; |
949 | } | 951 | } |
950 | return 0; | 952 | return 0; |
951 | } | 953 | } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) |
952 | else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) | ||
953 | set_color(par, regno, red, green, blue); | 954 | set_color(par, regno, red, green, blue); |
954 | 955 | ||
955 | return 0; | 956 | return 0; |
@@ -972,11 +973,9 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, | |||
972 | { | 973 | { |
973 | struct pm2fb_par *p = info->par; | 974 | struct pm2fb_par *p = info->par; |
974 | u32 base; | 975 | u32 base; |
975 | u32 depth; | 976 | u32 depth = (var->bits_per_pixel + 7) & ~7; |
976 | u32 xres; | 977 | u32 xres = (var->xres + 31) & ~31; |
977 | 978 | ||
978 | xres = (var->xres + 31) & ~31; | ||
979 | depth = (var->bits_per_pixel + 7) & ~7; | ||
980 | depth = (depth > 32) ? 32 : depth; | 979 | depth = (depth > 32) ? 32 : depth; |
981 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); | 980 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); |
982 | WAIT_FIFO(p, 1); | 981 | WAIT_FIFO(p, 1); |
@@ -1018,15 +1017,15 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info) | |||
1018 | break; | 1017 | break; |
1019 | case FB_BLANK_VSYNC_SUSPEND: | 1018 | case FB_BLANK_VSYNC_SUSPEND: |
1020 | /* VSync: Off */ | 1019 | /* VSync: Off */ |
1021 | video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); | 1020 | video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW); |
1022 | break; | 1021 | break; |
1023 | case FB_BLANK_HSYNC_SUSPEND: | 1022 | case FB_BLANK_HSYNC_SUSPEND: |
1024 | /* HSync: Off */ | 1023 | /* HSync: Off */ |
1025 | video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); | 1024 | video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW); |
1026 | break; | 1025 | break; |
1027 | case FB_BLANK_POWERDOWN: | 1026 | case FB_BLANK_POWERDOWN: |
1028 | /* HSync: Off, VSync: Off */ | 1027 | /* HSync: Off, VSync: Off */ |
1029 | video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); | 1028 | video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW); |
1030 | break; | 1029 | break; |
1031 | } | 1030 | } |
1032 | set_video(par, video); | 1031 | set_video(par, video); |
@@ -1042,48 +1041,20 @@ static int pm2fb_sync(struct fb_info *info) | |||
1042 | mb(); | 1041 | mb(); |
1043 | do { | 1042 | do { |
1044 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) | 1043 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) |
1045 | udelay(10); | 1044 | cpu_relax(); |
1046 | rmb(); | ||
1047 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); | 1045 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); |
1048 | 1046 | ||
1049 | return 0; | 1047 | return 0; |
1050 | } | 1048 | } |
1051 | 1049 | ||
1052 | /* | 1050 | static void pm2fb_fillrect(struct fb_info *info, |
1053 | * block operation. copy=0: rectangle fill, copy=1: rectangle copy. | ||
1054 | */ | ||
1055 | static void pm2fb_block_op(struct fb_info* info, int copy, | ||
1056 | s32 xsrc, s32 ysrc, | ||
1057 | s32 x, s32 y, s32 w, s32 h, | ||
1058 | u32 color) { | ||
1059 | struct pm2fb_par *par = info->par; | ||
1060 | |||
1061 | if (!w || !h) | ||
1062 | return; | ||
1063 | WAIT_FIFO(par, 5); | ||
1064 | pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | | ||
1065 | PM2F_CONFIG_FB_READ_SOURCE_ENABLE); | ||
1066 | if (copy) | ||
1067 | pm2_WR(par, PM2R_FB_SOURCE_DELTA, | ||
1068 | ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff)); | ||
1069 | else | ||
1070 | pm2_WR(par, PM2R_FB_BLOCK_COLOR, color); | ||
1071 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); | ||
1072 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); | ||
1073 | wmb(); | ||
1074 | pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | | ||
1075 | (x<xsrc ? PM2F_INCREASE_X : 0) | | ||
1076 | (y<ysrc ? PM2F_INCREASE_Y : 0) | | ||
1077 | (copy ? 0 : PM2F_RENDER_FASTFILL)); | ||
1078 | } | ||
1079 | |||
1080 | static void pm2fb_fillrect (struct fb_info *info, | ||
1081 | const struct fb_fillrect *region) | 1051 | const struct fb_fillrect *region) |
1082 | { | 1052 | { |
1053 | struct pm2fb_par *par = info->par; | ||
1083 | struct fb_fillrect modded; | 1054 | struct fb_fillrect modded; |
1084 | int vxres, vyres; | 1055 | int vxres, vyres; |
1085 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | 1056 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? |
1086 | ((u32*)info->pseudo_palette)[region->color] : region->color; | 1057 | ((u32 *)info->pseudo_palette)[region->color] : region->color; |
1087 | 1058 | ||
1088 | if (info->state != FBINFO_STATE_RUNNING) | 1059 | if (info->state != FBINFO_STATE_RUNNING) |
1089 | return; | 1060 | return; |
@@ -1098,31 +1069,46 @@ static void pm2fb_fillrect (struct fb_info *info, | |||
1098 | 1069 | ||
1099 | memcpy(&modded, region, sizeof(struct fb_fillrect)); | 1070 | memcpy(&modded, region, sizeof(struct fb_fillrect)); |
1100 | 1071 | ||
1101 | if(!modded.width || !modded.height || | 1072 | if (!modded.width || !modded.height || |
1102 | modded.dx >= vxres || modded.dy >= vyres) | 1073 | modded.dx >= vxres || modded.dy >= vyres) |
1103 | return; | 1074 | return; |
1104 | 1075 | ||
1105 | if(modded.dx + modded.width > vxres) | 1076 | if (modded.dx + modded.width > vxres) |
1106 | modded.width = vxres - modded.dx; | 1077 | modded.width = vxres - modded.dx; |
1107 | if(modded.dy + modded.height > vyres) | 1078 | if (modded.dy + modded.height > vyres) |
1108 | modded.height = vyres - modded.dy; | 1079 | modded.height = vyres - modded.dy; |
1109 | 1080 | ||
1110 | if(info->var.bits_per_pixel == 8) | 1081 | if (info->var.bits_per_pixel == 8) |
1111 | color |= color << 8; | 1082 | color |= color << 8; |
1112 | if(info->var.bits_per_pixel <= 16) | 1083 | if (info->var.bits_per_pixel <= 16) |
1113 | color |= color << 16; | 1084 | color |= color << 16; |
1114 | 1085 | ||
1115 | if(info->var.bits_per_pixel != 24) | 1086 | WAIT_FIFO(par, 3); |
1116 | pm2fb_block_op(info, 0, 0, 0, | 1087 | pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE); |
1117 | modded.dx, modded.dy, | 1088 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); |
1118 | modded.width, modded.height, color); | 1089 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); |
1119 | else | 1090 | if (info->var.bits_per_pixel != 24) { |
1120 | cfb_fillrect(info, region); | 1091 | WAIT_FIFO(par, 2); |
1092 | pm2_WR(par, PM2R_FB_BLOCK_COLOR, color); | ||
1093 | wmb(); | ||
1094 | pm2_WR(par, PM2R_RENDER, | ||
1095 | PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL); | ||
1096 | } else { | ||
1097 | WAIT_FIFO(par, 4); | ||
1098 | pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); | ||
1099 | pm2_WR(par, PM2R_CONSTANT_COLOR, color); | ||
1100 | wmb(); | ||
1101 | pm2_WR(par, PM2R_RENDER, | ||
1102 | PM2F_RENDER_RECTANGLE | | ||
1103 | PM2F_INCREASE_X | PM2F_INCREASE_Y ); | ||
1104 | pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); | ||
1105 | } | ||
1121 | } | 1106 | } |
1122 | 1107 | ||
1123 | static void pm2fb_copyarea(struct fb_info *info, | 1108 | static void pm2fb_copyarea(struct fb_info *info, |
1124 | const struct fb_copyarea *area) | 1109 | const struct fb_copyarea *area) |
1125 | { | 1110 | { |
1111 | struct pm2fb_par *par = info->par; | ||
1126 | struct fb_copyarea modded; | 1112 | struct fb_copyarea modded; |
1127 | u32 vxres, vyres; | 1113 | u32 vxres, vyres; |
1128 | 1114 | ||
@@ -1138,23 +1124,359 @@ static void pm2fb_copyarea(struct fb_info *info, | |||
1138 | vxres = info->var.xres_virtual; | 1124 | vxres = info->var.xres_virtual; |
1139 | vyres = info->var.yres_virtual; | 1125 | vyres = info->var.yres_virtual; |
1140 | 1126 | ||
1141 | if(!modded.width || !modded.height || | 1127 | if (!modded.width || !modded.height || |
1142 | modded.sx >= vxres || modded.sy >= vyres || | 1128 | modded.sx >= vxres || modded.sy >= vyres || |
1143 | modded.dx >= vxres || modded.dy >= vyres) | 1129 | modded.dx >= vxres || modded.dy >= vyres) |
1144 | return; | 1130 | return; |
1145 | 1131 | ||
1146 | if(modded.sx + modded.width > vxres) | 1132 | if (modded.sx + modded.width > vxres) |
1147 | modded.width = vxres - modded.sx; | 1133 | modded.width = vxres - modded.sx; |
1148 | if(modded.dx + modded.width > vxres) | 1134 | if (modded.dx + modded.width > vxres) |
1149 | modded.width = vxres - modded.dx; | 1135 | modded.width = vxres - modded.dx; |
1150 | if(modded.sy + modded.height > vyres) | 1136 | if (modded.sy + modded.height > vyres) |
1151 | modded.height = vyres - modded.sy; | 1137 | modded.height = vyres - modded.sy; |
1152 | if(modded.dy + modded.height > vyres) | 1138 | if (modded.dy + modded.height > vyres) |
1153 | modded.height = vyres - modded.dy; | 1139 | modded.height = vyres - modded.dy; |
1154 | 1140 | ||
1155 | pm2fb_block_op(info, 1, modded.sx, modded.sy, | 1141 | WAIT_FIFO(par, 5); |
1156 | modded.dx, modded.dy, | 1142 | pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | |
1157 | modded.width, modded.height, 0); | 1143 | PM2F_CONFIG_FB_READ_SOURCE_ENABLE); |
1144 | pm2_WR(par, PM2R_FB_SOURCE_DELTA, | ||
1145 | ((modded.sy - modded.dy) & 0xfff) << 16 | | ||
1146 | ((modded.sx - modded.dx) & 0xfff)); | ||
1147 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); | ||
1148 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); | ||
1149 | wmb(); | ||
1150 | pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | | ||
1151 | (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) | | ||
1152 | (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0)); | ||
1153 | } | ||
1154 | |||
1155 | static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
1156 | { | ||
1157 | struct pm2fb_par *par = info->par; | ||
1158 | u32 height = image->height; | ||
1159 | u32 fgx, bgx; | ||
1160 | const u32 *src = (const u32 *)image->data; | ||
1161 | u32 xres = (info->var.xres + 31) & ~31; | ||
1162 | |||
1163 | if (info->state != FBINFO_STATE_RUNNING) | ||
1164 | return; | ||
1165 | if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) { | ||
1166 | cfb_imageblit(info, image); | ||
1167 | return; | ||
1168 | } | ||
1169 | switch (info->fix.visual) { | ||
1170 | case FB_VISUAL_PSEUDOCOLOR: | ||
1171 | fgx = image->fg_color; | ||
1172 | bgx = image->bg_color; | ||
1173 | break; | ||
1174 | case FB_VISUAL_TRUECOLOR: | ||
1175 | default: | ||
1176 | fgx = par->palette[image->fg_color]; | ||
1177 | bgx = par->palette[image->bg_color]; | ||
1178 | break; | ||
1179 | } | ||
1180 | if (info->var.bits_per_pixel == 8) { | ||
1181 | fgx |= fgx << 8; | ||
1182 | bgx |= bgx << 8; | ||
1183 | } | ||
1184 | if (info->var.bits_per_pixel <= 16) { | ||
1185 | fgx |= fgx << 16; | ||
1186 | bgx |= bgx << 16; | ||
1187 | } | ||
1188 | |||
1189 | WAIT_FIFO(par, 13); | ||
1190 | pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres)); | ||
1191 | pm2_WR(par, PM2R_SCISSOR_MIN_XY, | ||
1192 | ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); | ||
1193 | pm2_WR(par, PM2R_SCISSOR_MAX_XY, | ||
1194 | (((image->dy + image->height) & 0x0fff) << 16) | | ||
1195 | ((image->dx + image->width) & 0x0fff)); | ||
1196 | pm2_WR(par, PM2R_SCISSOR_MODE, 1); | ||
1197 | /* GXcopy & UNIT_ENABLE */ | ||
1198 | pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1); | ||
1199 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, | ||
1200 | ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); | ||
1201 | pm2_WR(par, PM2R_RECTANGLE_SIZE, | ||
1202 | ((image->height & 0x0fff) << 16) | | ||
1203 | ((image->width) & 0x0fff)); | ||
1204 | if (info->var.bits_per_pixel == 24) { | ||
1205 | pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); | ||
1206 | /* clear area */ | ||
1207 | pm2_WR(par, PM2R_CONSTANT_COLOR, bgx); | ||
1208 | pm2_WR(par, PM2R_RENDER, | ||
1209 | PM2F_RENDER_RECTANGLE | | ||
1210 | PM2F_INCREASE_X | PM2F_INCREASE_Y); | ||
1211 | /* BitMapPackEachScanline & invert bits and byte order*/ | ||
1212 | /* force background */ | ||
1213 | pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7)); | ||
1214 | pm2_WR(par, PM2R_CONSTANT_COLOR, fgx); | ||
1215 | pm2_WR(par, PM2R_RENDER, | ||
1216 | PM2F_RENDER_RECTANGLE | | ||
1217 | PM2F_INCREASE_X | PM2F_INCREASE_Y | | ||
1218 | PM2F_RENDER_SYNC_ON_BIT_MASK); | ||
1219 | } else { | ||
1220 | pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); | ||
1221 | /* clear area */ | ||
1222 | pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx); | ||
1223 | pm2_WR(par, PM2R_RENDER, | ||
1224 | PM2F_RENDER_RECTANGLE | | ||
1225 | PM2F_RENDER_FASTFILL | | ||
1226 | PM2F_INCREASE_X | PM2F_INCREASE_Y); | ||
1227 | /* invert bits and byte order*/ | ||
1228 | pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7)); | ||
1229 | pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx); | ||
1230 | pm2_WR(par, PM2R_RENDER, | ||
1231 | PM2F_RENDER_RECTANGLE | | ||
1232 | PM2F_INCREASE_X | PM2F_INCREASE_Y | | ||
1233 | PM2F_RENDER_FASTFILL | | ||
1234 | PM2F_RENDER_SYNC_ON_BIT_MASK); | ||
1235 | } | ||
1236 | |||
1237 | while (height--) { | ||
1238 | int width = ((image->width + 7) >> 3) | ||
1239 | + info->pixmap.scan_align - 1; | ||
1240 | width >>= 2; | ||
1241 | WAIT_FIFO(par, width); | ||
1242 | while (width--) { | ||
1243 | pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src); | ||
1244 | src++; | ||
1245 | } | ||
1246 | } | ||
1247 | WAIT_FIFO(par, 3); | ||
1248 | pm2_WR(par, PM2R_RASTERIZER_MODE, 0); | ||
1249 | pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); | ||
1250 | pm2_WR(par, PM2R_SCISSOR_MODE, 0); | ||
1251 | } | ||
1252 | |||
1253 | /* | ||
1254 | * Hardware cursor support. | ||
1255 | */ | ||
1256 | static const u8 cursor_bits_lookup[16] = { | ||
1257 | 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, | ||
1258 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 | ||
1259 | }; | ||
1260 | |||
1261 | static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
1262 | { | ||
1263 | struct pm2fb_par *par = info->par; | ||
1264 | u8 mode = PM2F_CURSORMODE_TYPE_X; | ||
1265 | int x = cursor->image.dx - info->var.xoffset; | ||
1266 | int y = cursor->image.dy - info->var.yoffset; | ||
1267 | |||
1268 | if (cursor->enable) | ||
1269 | mode |= PM2F_CURSORMODE_CURSOR_ENABLE; | ||
1270 | |||
1271 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode); | ||
1272 | |||
1273 | if (!cursor->enable) | ||
1274 | x = 2047; /* push it outside display */ | ||
1275 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff); | ||
1276 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf); | ||
1277 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff); | ||
1278 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf); | ||
1279 | |||
1280 | /* | ||
1281 | * If the cursor is not be changed this means either we want the | ||
1282 | * current cursor state (if enable is set) or we want to query what | ||
1283 | * we can do with the cursor (if enable is not set) | ||
1284 | */ | ||
1285 | if (!cursor->set) | ||
1286 | return 0; | ||
1287 | |||
1288 | if (cursor->set & FB_CUR_SETHOT) { | ||
1289 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT, | ||
1290 | cursor->hot.x & 0x3f); | ||
1291 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT, | ||
1292 | cursor->hot.y & 0x3f); | ||
1293 | } | ||
1294 | |||
1295 | if (cursor->set & FB_CUR_SETCMAP) { | ||
1296 | u32 fg_idx = cursor->image.fg_color; | ||
1297 | u32 bg_idx = cursor->image.bg_color; | ||
1298 | struct fb_cmap cmap = info->cmap; | ||
1299 | |||
1300 | /* the X11 driver says one should use these color registers */ | ||
1301 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8); | ||
1302 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0, | ||
1303 | cmap.red[bg_idx] >> 8 ); | ||
1304 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1, | ||
1305 | cmap.green[bg_idx] >> 8 ); | ||
1306 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2, | ||
1307 | cmap.blue[bg_idx] >> 8 ); | ||
1308 | |||
1309 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3, | ||
1310 | cmap.red[fg_idx] >> 8 ); | ||
1311 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4, | ||
1312 | cmap.green[fg_idx] >> 8 ); | ||
1313 | pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5, | ||
1314 | cmap.blue[fg_idx] >> 8 ); | ||
1315 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); | ||
1316 | } | ||
1317 | |||
1318 | if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { | ||
1319 | u8 *bitmap = (u8 *)cursor->image.data; | ||
1320 | u8 *mask = (u8 *)cursor->mask; | ||
1321 | int i; | ||
1322 | int pos = PM2VI_RD_CURSOR_PATTERN; | ||
1323 | |||
1324 | for (i = 0; i < cursor->image.height; i++) { | ||
1325 | int j = (cursor->image.width + 7) >> 3; | ||
1326 | int k = 8 - j; | ||
1327 | |||
1328 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); | ||
1329 | |||
1330 | for (; j > 0; j--) { | ||
1331 | u8 data = *bitmap ^ *mask; | ||
1332 | |||
1333 | if (cursor->rop == ROP_COPY) | ||
1334 | data = *mask & *bitmap; | ||
1335 | /* Upper 4 bits of bitmap data */ | ||
1336 | pm2v_RDAC_WR(par, pos++, | ||
1337 | cursor_bits_lookup[data >> 4] | | ||
1338 | (cursor_bits_lookup[*mask >> 4] << 1)); | ||
1339 | /* Lower 4 bits of bitmap */ | ||
1340 | pm2v_RDAC_WR(par, pos++, | ||
1341 | cursor_bits_lookup[data & 0xf] | | ||
1342 | (cursor_bits_lookup[*mask & 0xf] << 1)); | ||
1343 | bitmap++; | ||
1344 | mask++; | ||
1345 | } | ||
1346 | for (; k > 0; k--) { | ||
1347 | pm2v_RDAC_WR(par, pos++, 0); | ||
1348 | pm2v_RDAC_WR(par, pos++, 0); | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) { | ||
1353 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); | ||
1354 | pm2v_RDAC_WR(par, pos++, 0); | ||
1355 | } | ||
1356 | |||
1357 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); | ||
1358 | } | ||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
1363 | { | ||
1364 | struct pm2fb_par *par = info->par; | ||
1365 | u8 mode; | ||
1366 | |||
1367 | if (!hwcursor) | ||
1368 | return -EINVAL; /* just to force soft_cursor() call */ | ||
1369 | |||
1370 | /* Too large of a cursor or wrong bpp :-( */ | ||
1371 | if (cursor->image.width > 64 || | ||
1372 | cursor->image.height > 64 || | ||
1373 | cursor->image.depth > 1) | ||
1374 | return -EINVAL; | ||
1375 | |||
1376 | if (par->type == PM2_TYPE_PERMEDIA2V) | ||
1377 | return pm2vfb_cursor(info, cursor); | ||
1378 | |||
1379 | mode = 0x40; | ||
1380 | if (cursor->enable) | ||
1381 | mode = 0x43; | ||
1382 | |||
1383 | pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode); | ||
1384 | |||
1385 | /* | ||
1386 | * If the cursor is not be changed this means either we want the | ||
1387 | * current cursor state (if enable is set) or we want to query what | ||
1388 | * we can do with the cursor (if enable is not set) | ||
1389 | */ | ||
1390 | if (!cursor->set) | ||
1391 | return 0; | ||
1392 | |||
1393 | if (cursor->set & FB_CUR_SETPOS) { | ||
1394 | int x = cursor->image.dx - info->var.xoffset + 63; | ||
1395 | int y = cursor->image.dy - info->var.yoffset + 63; | ||
1396 | |||
1397 | WAIT_FIFO(par, 4); | ||
1398 | pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff); | ||
1399 | pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7); | ||
1400 | pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff); | ||
1401 | pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7); | ||
1402 | } | ||
1403 | |||
1404 | if (cursor->set & FB_CUR_SETCMAP) { | ||
1405 | u32 fg_idx = cursor->image.fg_color; | ||
1406 | u32 bg_idx = cursor->image.bg_color; | ||
1407 | |||
1408 | WAIT_FIFO(par, 7); | ||
1409 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1); | ||
1410 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1411 | info->cmap.red[bg_idx] >> 8); | ||
1412 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1413 | info->cmap.green[bg_idx] >> 8); | ||
1414 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1415 | info->cmap.blue[bg_idx] >> 8); | ||
1416 | |||
1417 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1418 | info->cmap.red[fg_idx] >> 8); | ||
1419 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1420 | info->cmap.green[fg_idx] >> 8); | ||
1421 | pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, | ||
1422 | info->cmap.blue[fg_idx] >> 8); | ||
1423 | } | ||
1424 | |||
1425 | if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { | ||
1426 | u8 *bitmap = (u8 *)cursor->image.data; | ||
1427 | u8 *mask = (u8 *)cursor->mask; | ||
1428 | int i; | ||
1429 | |||
1430 | WAIT_FIFO(par, 1); | ||
1431 | pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); | ||
1432 | |||
1433 | for (i = 0; i < cursor->image.height; i++) { | ||
1434 | int j = (cursor->image.width + 7) >> 3; | ||
1435 | int k = 8 - j; | ||
1436 | |||
1437 | WAIT_FIFO(par, 8); | ||
1438 | for (; j > 0; j--) { | ||
1439 | u8 data = *bitmap ^ *mask; | ||
1440 | |||
1441 | if (cursor->rop == ROP_COPY) | ||
1442 | data = *mask & *bitmap; | ||
1443 | /* bitmap data */ | ||
1444 | pm2_WR(par, PM2R_RD_CURSOR_DATA, data); | ||
1445 | bitmap++; | ||
1446 | mask++; | ||
1447 | } | ||
1448 | for (; k > 0; k--) | ||
1449 | pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); | ||
1450 | } | ||
1451 | for (; i < 64; i++) { | ||
1452 | int j = 8; | ||
1453 | WAIT_FIFO(par, 8); | ||
1454 | while (j-- > 0) | ||
1455 | pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); | ||
1456 | } | ||
1457 | |||
1458 | mask = (u8 *)cursor->mask; | ||
1459 | for (i = 0; i < cursor->image.height; i++) { | ||
1460 | int j = (cursor->image.width + 7) >> 3; | ||
1461 | int k = 8 - j; | ||
1462 | |||
1463 | WAIT_FIFO(par, 8); | ||
1464 | for (; j > 0; j--) { | ||
1465 | /* mask */ | ||
1466 | pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask); | ||
1467 | mask++; | ||
1468 | } | ||
1469 | for (; k > 0; k--) | ||
1470 | pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); | ||
1471 | } | ||
1472 | for (; i < 64; i++) { | ||
1473 | int j = 8; | ||
1474 | WAIT_FIFO(par, 8); | ||
1475 | while (j-- > 0) | ||
1476 | pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); | ||
1477 | } | ||
1478 | } | ||
1479 | return 0; | ||
1158 | } | 1480 | } |
1159 | 1481 | ||
1160 | /* ------------ Hardware Independent Functions ------------ */ | 1482 | /* ------------ Hardware Independent Functions ------------ */ |
@@ -1172,8 +1494,9 @@ static struct fb_ops pm2fb_ops = { | |||
1172 | .fb_pan_display = pm2fb_pan_display, | 1494 | .fb_pan_display = pm2fb_pan_display, |
1173 | .fb_fillrect = pm2fb_fillrect, | 1495 | .fb_fillrect = pm2fb_fillrect, |
1174 | .fb_copyarea = pm2fb_copyarea, | 1496 | .fb_copyarea = pm2fb_copyarea, |
1175 | .fb_imageblit = cfb_imageblit, | 1497 | .fb_imageblit = pm2fb_imageblit, |
1176 | .fb_sync = pm2fb_sync, | 1498 | .fb_sync = pm2fb_sync, |
1499 | .fb_cursor = pm2fb_cursor, | ||
1177 | }; | 1500 | }; |
1178 | 1501 | ||
1179 | /* | 1502 | /* |
@@ -1194,16 +1517,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1194 | { | 1517 | { |
1195 | struct pm2fb_par *default_par; | 1518 | struct pm2fb_par *default_par; |
1196 | struct fb_info *info; | 1519 | struct fb_info *info; |
1197 | int err, err_retval = -ENXIO; | 1520 | int err; |
1521 | int retval = -ENXIO; | ||
1198 | 1522 | ||
1199 | err = pci_enable_device(pdev); | 1523 | err = pci_enable_device(pdev); |
1200 | if ( err ) { | 1524 | if (err) { |
1201 | printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); | 1525 | printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); |
1202 | return err; | 1526 | return err; |
1203 | } | 1527 | } |
1204 | 1528 | ||
1205 | info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); | 1529 | info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); |
1206 | if ( !info ) | 1530 | if (!info) |
1207 | return -ENOMEM; | 1531 | return -ENOMEM; |
1208 | default_par = info->par; | 1532 | default_par = info->par; |
1209 | 1533 | ||
@@ -1236,14 +1560,14 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1236 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); | 1560 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); |
1237 | 1561 | ||
1238 | /* Registers - request region and map it. */ | 1562 | /* Registers - request region and map it. */ |
1239 | if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, | 1563 | if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, |
1240 | "pm2fb regbase") ) { | 1564 | "pm2fb regbase")) { |
1241 | printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); | 1565 | printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); |
1242 | goto err_exit_neither; | 1566 | goto err_exit_neither; |
1243 | } | 1567 | } |
1244 | default_par->v_regs = | 1568 | default_par->v_regs = |
1245 | ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); | 1569 | ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); |
1246 | if ( !default_par->v_regs ) { | 1570 | if (!default_par->v_regs) { |
1247 | printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", | 1571 | printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", |
1248 | pm2fb_fix.id); | 1572 | pm2fb_fix.id); |
1249 | release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); | 1573 | release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); |
@@ -1258,72 +1582,101 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1258 | default_par->mem_control, default_par->boot_address, | 1582 | default_par->mem_control, default_par->boot_address, |
1259 | default_par->mem_config); | 1583 | default_par->mem_config); |
1260 | 1584 | ||
1261 | if(default_par->mem_control == 0 && | 1585 | if (default_par->mem_control == 0 && |
1262 | default_par->boot_address == 0x31 && | 1586 | default_par->boot_address == 0x31 && |
1263 | default_par->mem_config == 0x259fffff) { | 1587 | default_par->mem_config == 0x259fffff) { |
1264 | default_par->memclock = CVPPC_MEMCLOCK; | 1588 | default_par->memclock = CVPPC_MEMCLOCK; |
1265 | default_par->mem_control=0; | 1589 | default_par->mem_control = 0; |
1266 | default_par->boot_address=0x20; | 1590 | default_par->boot_address = 0x20; |
1267 | default_par->mem_config=0xe6002021; | 1591 | default_par->mem_config = 0xe6002021; |
1268 | if (pdev->subsystem_vendor == 0x1048 && | 1592 | if (pdev->subsystem_vendor == 0x1048 && |
1269 | pdev->subsystem_device == 0x0a31) { | 1593 | pdev->subsystem_device == 0x0a31) { |
1270 | DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", | 1594 | DPRINTK("subsystem_vendor: %04x, " |
1595 | "subsystem_device: %04x\n", | ||
1271 | pdev->subsystem_vendor, pdev->subsystem_device); | 1596 | pdev->subsystem_vendor, pdev->subsystem_device); |
1272 | DPRINTK("We have not been initialized by VGA BIOS " | 1597 | DPRINTK("We have not been initialized by VGA BIOS and " |
1273 | "and are running on an Elsa Winner 2000 Office\n"); | 1598 | "are running on an Elsa Winner 2000 Office\n"); |
1274 | DPRINTK("Initializing card timings manually...\n"); | 1599 | DPRINTK("Initializing card timings manually...\n"); |
1275 | default_par->memclock=70000; | 1600 | default_par->memclock = 100000; |
1276 | } | 1601 | } |
1277 | if (pdev->subsystem_vendor == 0x3d3d && | 1602 | if (pdev->subsystem_vendor == 0x3d3d && |
1278 | pdev->subsystem_device == 0x0100) { | 1603 | pdev->subsystem_device == 0x0100) { |
1279 | DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", | 1604 | DPRINTK("subsystem_vendor: %04x, " |
1605 | "subsystem_device: %04x\n", | ||
1280 | pdev->subsystem_vendor, pdev->subsystem_device); | 1606 | pdev->subsystem_vendor, pdev->subsystem_device); |
1281 | DPRINTK("We have not been initialized by VGA BIOS " | 1607 | DPRINTK("We have not been initialized by VGA BIOS and " |
1282 | "and are running on an 3dlabs reference board\n"); | 1608 | "are running on an 3dlabs reference board\n"); |
1283 | DPRINTK("Initializing card timings manually...\n"); | 1609 | DPRINTK("Initializing card timings manually...\n"); |
1284 | default_par->memclock=74894; | 1610 | default_par->memclock = 74894; |
1285 | } | 1611 | } |
1286 | } | 1612 | } |
1287 | 1613 | ||
1288 | /* Now work out how big lfb is going to be. */ | 1614 | /* Now work out how big lfb is going to be. */ |
1289 | switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { | 1615 | switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { |
1290 | case PM2F_MEM_BANKS_1: | 1616 | case PM2F_MEM_BANKS_1: |
1291 | pm2fb_fix.smem_len=0x200000; | 1617 | pm2fb_fix.smem_len = 0x200000; |
1292 | break; | 1618 | break; |
1293 | case PM2F_MEM_BANKS_2: | 1619 | case PM2F_MEM_BANKS_2: |
1294 | pm2fb_fix.smem_len=0x400000; | 1620 | pm2fb_fix.smem_len = 0x400000; |
1295 | break; | 1621 | break; |
1296 | case PM2F_MEM_BANKS_3: | 1622 | case PM2F_MEM_BANKS_3: |
1297 | pm2fb_fix.smem_len=0x600000; | 1623 | pm2fb_fix.smem_len = 0x600000; |
1298 | break; | 1624 | break; |
1299 | case PM2F_MEM_BANKS_4: | 1625 | case PM2F_MEM_BANKS_4: |
1300 | pm2fb_fix.smem_len=0x800000; | 1626 | pm2fb_fix.smem_len = 0x800000; |
1301 | break; | 1627 | break; |
1302 | } | 1628 | } |
1303 | pm2fb_fix.smem_start = pci_resource_start(pdev, 1); | 1629 | pm2fb_fix.smem_start = pci_resource_start(pdev, 1); |
1304 | 1630 | ||
1305 | /* Linear frame buffer - request region and map it. */ | 1631 | /* Linear frame buffer - request region and map it. */ |
1306 | if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, | 1632 | if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, |
1307 | "pm2fb smem") ) { | 1633 | "pm2fb smem")) { |
1308 | printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); | 1634 | printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); |
1309 | goto err_exit_mmio; | 1635 | goto err_exit_mmio; |
1310 | } | 1636 | } |
1311 | info->screen_base = | 1637 | info->screen_base = |
1312 | ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); | 1638 | ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); |
1313 | if ( !info->screen_base ) { | 1639 | if (!info->screen_base) { |
1314 | printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); | 1640 | printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); |
1315 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); | 1641 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); |
1316 | goto err_exit_mmio; | 1642 | goto err_exit_mmio; |
1317 | } | 1643 | } |
1318 | 1644 | ||
1645 | #ifdef CONFIG_MTRR | ||
1646 | default_par->mtrr_handle = -1; | ||
1647 | if (!nomtrr) | ||
1648 | default_par->mtrr_handle = | ||
1649 | mtrr_add(pm2fb_fix.smem_start, | ||
1650 | pm2fb_fix.smem_len, | ||
1651 | MTRR_TYPE_WRCOMB, 1); | ||
1652 | #endif | ||
1653 | |||
1319 | info->fbops = &pm2fb_ops; | 1654 | info->fbops = &pm2fb_ops; |
1320 | info->fix = pm2fb_fix; | 1655 | info->fix = pm2fb_fix; |
1321 | info->pseudo_palette = default_par->palette; | 1656 | info->pseudo_palette = default_par->palette; |
1322 | info->flags = FBINFO_DEFAULT | | 1657 | info->flags = FBINFO_DEFAULT | |
1323 | FBINFO_HWACCEL_YPAN | | 1658 | FBINFO_HWACCEL_YPAN | |
1324 | FBINFO_HWACCEL_COPYAREA | | 1659 | FBINFO_HWACCEL_COPYAREA | |
1660 | FBINFO_HWACCEL_IMAGEBLIT | | ||
1325 | FBINFO_HWACCEL_FILLRECT; | 1661 | FBINFO_HWACCEL_FILLRECT; |
1326 | 1662 | ||
1663 | info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL); | ||
1664 | if (!info->pixmap.addr) { | ||
1665 | retval = -ENOMEM; | ||
1666 | goto err_exit_pixmap; | ||
1667 | } | ||
1668 | info->pixmap.size = PM2_PIXMAP_SIZE; | ||
1669 | info->pixmap.buf_align = 4; | ||
1670 | info->pixmap.scan_align = 4; | ||
1671 | info->pixmap.access_align = 32; | ||
1672 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
1673 | |||
1674 | if (noaccel) { | ||
1675 | printk(KERN_DEBUG "disabling acceleration\n"); | ||
1676 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
1677 | info->pixmap.scan_align = 1; | ||
1678 | } | ||
1679 | |||
1327 | if (!mode) | 1680 | if (!mode) |
1328 | mode = "640x480@60"; | 1681 | mode = "640x480@60"; |
1329 | 1682 | ||
@@ -1350,6 +1703,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1350 | err_exit_all: | 1703 | err_exit_all: |
1351 | fb_dealloc_cmap(&info->cmap); | 1704 | fb_dealloc_cmap(&info->cmap); |
1352 | err_exit_both: | 1705 | err_exit_both: |
1706 | kfree(info->pixmap.addr); | ||
1707 | err_exit_pixmap: | ||
1353 | iounmap(info->screen_base); | 1708 | iounmap(info->screen_base); |
1354 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); | 1709 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); |
1355 | err_exit_mmio: | 1710 | err_exit_mmio: |
@@ -1357,7 +1712,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1357 | release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); | 1712 | release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); |
1358 | err_exit_neither: | 1713 | err_exit_neither: |
1359 | framebuffer_release(info); | 1714 | framebuffer_release(info); |
1360 | return err_retval; | 1715 | return retval; |
1361 | } | 1716 | } |
1362 | 1717 | ||
1363 | /** | 1718 | /** |
@@ -1369,34 +1724,34 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1369 | */ | 1724 | */ |
1370 | static void __devexit pm2fb_remove(struct pci_dev *pdev) | 1725 | static void __devexit pm2fb_remove(struct pci_dev *pdev) |
1371 | { | 1726 | { |
1372 | struct fb_info* info = pci_get_drvdata(pdev); | 1727 | struct fb_info *info = pci_get_drvdata(pdev); |
1373 | struct fb_fix_screeninfo* fix = &info->fix; | 1728 | struct fb_fix_screeninfo *fix = &info->fix; |
1374 | struct pm2fb_par *par = info->par; | 1729 | struct pm2fb_par *par = info->par; |
1375 | 1730 | ||
1376 | unregister_framebuffer(info); | 1731 | unregister_framebuffer(info); |
1377 | 1732 | ||
1733 | #ifdef CONFIG_MTRR | ||
1734 | if (par->mtrr_handle >= 0) | ||
1735 | mtrr_del(par->mtrr_handle, info->fix.smem_start, | ||
1736 | info->fix.smem_len); | ||
1737 | #endif /* CONFIG_MTRR */ | ||
1378 | iounmap(info->screen_base); | 1738 | iounmap(info->screen_base); |
1379 | release_mem_region(fix->smem_start, fix->smem_len); | 1739 | release_mem_region(fix->smem_start, fix->smem_len); |
1380 | iounmap(par->v_regs); | 1740 | iounmap(par->v_regs); |
1381 | release_mem_region(fix->mmio_start, fix->mmio_len); | 1741 | release_mem_region(fix->mmio_start, fix->mmio_len); |
1382 | 1742 | ||
1383 | pci_set_drvdata(pdev, NULL); | 1743 | pci_set_drvdata(pdev, NULL); |
1744 | kfree(info->pixmap.addr); | ||
1384 | kfree(info); | 1745 | kfree(info); |
1385 | } | 1746 | } |
1386 | 1747 | ||
1387 | static struct pci_device_id pm2fb_id_table[] = { | 1748 | static struct pci_device_id pm2fb_id_table[] = { |
1388 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, | 1749 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, |
1389 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | 1750 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
1390 | 0xff0000, 0 }, | ||
1391 | { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, | 1751 | { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, |
1392 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | 1752 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
1393 | 0xff0000, 0 }, | ||
1394 | { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, | ||
1395 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | ||
1396 | 0xff0000, 0 }, | ||
1397 | { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, | 1753 | { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, |
1398 | PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8, | 1754 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
1399 | 0xff00, 0 }, | ||
1400 | { 0, } | 1755 | { 0, } |
1401 | }; | 1756 | }; |
1402 | 1757 | ||
@@ -1418,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table); | |||
1418 | */ | 1773 | */ |
1419 | static int __init pm2fb_setup(char *options) | 1774 | static int __init pm2fb_setup(char *options) |
1420 | { | 1775 | { |
1421 | char* this_opt; | 1776 | char *this_opt; |
1422 | 1777 | ||
1423 | if (!options || !*options) | 1778 | if (!options || !*options) |
1424 | return 0; | 1779 | return 0; |
@@ -1426,13 +1781,20 @@ static int __init pm2fb_setup(char *options) | |||
1426 | while ((this_opt = strsep(&options, ",")) != NULL) { | 1781 | while ((this_opt = strsep(&options, ",")) != NULL) { |
1427 | if (!*this_opt) | 1782 | if (!*this_opt) |
1428 | continue; | 1783 | continue; |
1429 | if(!strcmp(this_opt, "lowhsync")) { | 1784 | if (!strcmp(this_opt, "lowhsync")) |
1430 | lowhsync = 1; | 1785 | lowhsync = 1; |
1431 | } else if(!strcmp(this_opt, "lowvsync")) { | 1786 | else if (!strcmp(this_opt, "lowvsync")) |
1432 | lowvsync = 1; | 1787 | lowvsync = 1; |
1433 | } else { | 1788 | else if (!strncmp(this_opt, "hwcursor=", 9)) |
1789 | hwcursor = simple_strtoul(this_opt + 9, NULL, 0); | ||
1790 | #ifdef CONFIG_MTRR | ||
1791 | else if (!strncmp(this_opt, "nomtrr", 6)) | ||
1792 | nomtrr = 1; | ||
1793 | #endif | ||
1794 | else if (!strncmp(this_opt, "noaccel", 7)) | ||
1795 | noaccel = 1; | ||
1796 | else | ||
1434 | mode = this_opt; | 1797 | mode = this_opt; |
1435 | } | ||
1436 | } | 1798 | } |
1437 | return 0; | 1799 | return 0; |
1438 | } | 1800 | } |
@@ -1474,6 +1836,15 @@ module_param(lowhsync, bool, 0); | |||
1474 | MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); | 1836 | MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); |
1475 | module_param(lowvsync, bool, 0); | 1837 | module_param(lowvsync, bool, 0); |
1476 | MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); | 1838 | MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); |
1839 | module_param(noaccel, bool, 0); | ||
1840 | MODULE_PARM_DESC(noaccel, "Disable acceleration"); | ||
1841 | module_param(hwcursor, int, 0644); | ||
1842 | MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " | ||
1843 | "(1=enable, 0=disable, default=1)"); | ||
1844 | #ifdef CONFIG_MTRR | ||
1845 | module_param(nomtrr, bool, 0); | ||
1846 | MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); | ||
1847 | #endif | ||
1477 | 1848 | ||
1478 | MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); | 1849 | MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); |
1479 | MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); | 1850 | MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5b3f54c0918e..070659992c18 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c | |||
@@ -32,6 +32,9 @@ | |||
32 | #include <linux/fb.h> | 32 | #include <linux/fb.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #ifdef CONFIG_MTRR | ||
36 | #include <asm/mtrr.h> | ||
37 | #endif | ||
35 | 38 | ||
36 | #include <video/pm3fb.h> | 39 | #include <video/pm3fb.h> |
37 | 40 | ||
@@ -41,15 +44,25 @@ | |||
41 | 44 | ||
42 | #undef PM3FB_MASTER_DEBUG | 45 | #undef PM3FB_MASTER_DEBUG |
43 | #ifdef PM3FB_MASTER_DEBUG | 46 | #ifdef PM3FB_MASTER_DEBUG |
44 | #define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) | 47 | #define DPRINTK(a, b...) \ |
48 | printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) | ||
45 | #else | 49 | #else |
46 | #define DPRINTK(a,b...) | 50 | #define DPRINTK(a, b...) |
47 | #endif | 51 | #endif |
48 | 52 | ||
53 | #define PM3_PIXMAP_SIZE (2048 * 4) | ||
54 | |||
49 | /* | 55 | /* |
50 | * Driver data | 56 | * Driver data |
51 | */ | 57 | */ |
58 | static int hwcursor = 1; | ||
52 | static char *mode_option __devinitdata; | 59 | static char *mode_option __devinitdata; |
60 | static int noaccel __devinitdata; | ||
61 | |||
62 | /* mtrr option */ | ||
63 | #ifdef CONFIG_MTRR | ||
64 | static int nomtrr __devinitdata; | ||
65 | #endif | ||
53 | 66 | ||
54 | /* | 67 | /* |
55 | * This structure defines the hardware state of the graphics card. Normally | 68 | * This structure defines the hardware state of the graphics card. Normally |
@@ -61,8 +74,9 @@ static char *mode_option __devinitdata; | |||
61 | struct pm3_par { | 74 | struct pm3_par { |
62 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ | 75 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ |
63 | u32 video; /* video flags before blanking */ | 76 | u32 video; /* video flags before blanking */ |
64 | u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ | 77 | u32 base; /* screen base in 128 bits unit */ |
65 | u32 palette[16]; | 78 | u32 palette[16]; |
79 | int mtrr_handle; | ||
66 | }; | 80 | }; |
67 | 81 | ||
68 | /* | 82 | /* |
@@ -96,7 +110,8 @@ static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) | |||
96 | 110 | ||
97 | static inline void PM3_WAIT(struct pm3_par *par, u32 n) | 111 | static inline void PM3_WAIT(struct pm3_par *par, u32 n) |
98 | { | 112 | { |
99 | while (PM3_READ_REG(par, PM3InFIFOSpace) < n); | 113 | while (PM3_READ_REG(par, PM3InFIFOSpace) < n) |
114 | cpu_relax(); | ||
100 | } | 115 | } |
101 | 116 | ||
102 | static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) | 117 | static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) |
@@ -133,7 +148,7 @@ static void pm3fb_clear_colormap(struct pm3_par *par, | |||
133 | 148 | ||
134 | } | 149 | } |
135 | 150 | ||
136 | /* Calculating various clock parameter */ | 151 | /* Calculating various clock parameters */ |
137 | static void pm3fb_calculate_clock(unsigned long reqclock, | 152 | static void pm3fb_calculate_clock(unsigned long reqclock, |
138 | unsigned char *prescale, | 153 | unsigned char *prescale, |
139 | unsigned char *feedback, | 154 | unsigned char *feedback, |
@@ -164,7 +179,7 @@ static void pm3fb_calculate_clock(unsigned long reqclock, | |||
164 | 179 | ||
165 | static inline int pm3fb_depth(const struct fb_var_screeninfo *var) | 180 | static inline int pm3fb_depth(const struct fb_var_screeninfo *var) |
166 | { | 181 | { |
167 | if ( var->bits_per_pixel == 16 ) | 182 | if (var->bits_per_pixel == 16) |
168 | return var->red.length + var->green.length | 183 | return var->red.length + var->green.length |
169 | + var->blue.length; | 184 | + var->blue.length; |
170 | 185 | ||
@@ -195,8 +210,8 @@ static int pm3fb_sync(struct fb_info *info) | |||
195 | PM3_WRITE_REG(par, PM3Sync, 0); | 210 | PM3_WRITE_REG(par, PM3Sync, 0); |
196 | mb(); | 211 | mb(); |
197 | do { | 212 | do { |
198 | while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); | 213 | while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0) |
199 | rmb(); | 214 | cpu_relax(); |
200 | } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); | 215 | } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); |
201 | 216 | ||
202 | return 0; | 217 | return 0; |
@@ -276,15 +291,22 @@ static void pm3fb_init_engine(struct fb_info *info) | |||
276 | 291 | ||
277 | PM3_WAIT(par, 2); | 292 | PM3_WAIT(par, 2); |
278 | { | 293 | { |
279 | unsigned long rm = 1; | 294 | /* invert bits in bitmask */ |
295 | unsigned long rm = 1 | (3 << 7); | ||
280 | switch (info->var.bits_per_pixel) { | 296 | switch (info->var.bits_per_pixel) { |
281 | case 8: | 297 | case 8: |
282 | PM3_WRITE_REG(par, PM3PixelSize, | 298 | PM3_WRITE_REG(par, PM3PixelSize, |
283 | PM3PixelSize_GLOBAL_8BIT); | 299 | PM3PixelSize_GLOBAL_8BIT); |
300 | #ifdef __BIG_ENDIAN | ||
301 | rm |= 3 << 15; | ||
302 | #endif | ||
284 | break; | 303 | break; |
285 | case 16: | 304 | case 16: |
286 | PM3_WRITE_REG(par, PM3PixelSize, | 305 | PM3_WRITE_REG(par, PM3PixelSize, |
287 | PM3PixelSize_GLOBAL_16BIT); | 306 | PM3PixelSize_GLOBAL_16BIT); |
307 | #ifdef __BIG_ENDIAN | ||
308 | rm |= 2 << 15; | ||
309 | #endif | ||
288 | break; | 310 | break; |
289 | case 32: | 311 | case 32: |
290 | PM3_WRITE_REG(par, PM3PixelSize, | 312 | PM3_WRITE_REG(par, PM3PixelSize, |
@@ -342,7 +364,7 @@ static void pm3fb_init_engine(struct fb_info *info) | |||
342 | 364 | ||
343 | PM3_WRITE_REG(par, PM3dXDom, 0x0); | 365 | PM3_WRITE_REG(par, PM3dXDom, 0x0); |
344 | PM3_WRITE_REG(par, PM3dXSub, 0x0); | 366 | PM3_WRITE_REG(par, PM3dXSub, 0x0); |
345 | PM3_WRITE_REG(par, PM3dY, (1 << 16)); | 367 | PM3_WRITE_REG(par, PM3dY, 1 << 16); |
346 | PM3_WRITE_REG(par, PM3StartXDom, 0x0); | 368 | PM3_WRITE_REG(par, PM3StartXDom, 0x0); |
347 | PM3_WRITE_REG(par, PM3StartXSub, 0x0); | 369 | PM3_WRITE_REG(par, PM3StartXSub, 0x0); |
348 | PM3_WRITE_REG(par, PM3StartY, 0x0); | 370 | PM3_WRITE_REG(par, PM3StartY, 0x0); |
@@ -357,71 +379,350 @@ static void pm3fb_init_engine(struct fb_info *info) | |||
357 | pm3fb_sync(info); | 379 | pm3fb_sync(info); |
358 | } | 380 | } |
359 | 381 | ||
360 | static void pm3fb_fillrect (struct fb_info *info, | 382 | static void pm3fb_fillrect(struct fb_info *info, |
361 | const struct fb_fillrect *region) | 383 | const struct fb_fillrect *region) |
362 | { | 384 | { |
363 | struct pm3_par *par = info->par; | 385 | struct pm3_par *par = info->par; |
364 | struct fb_fillrect modded; | 386 | struct fb_fillrect modded; |
365 | int vxres, vyres; | 387 | int vxres, vyres; |
388 | int rop; | ||
366 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | 389 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? |
367 | ((u32*)info->pseudo_palette)[region->color] : region->color; | 390 | ((u32 *)info->pseudo_palette)[region->color] : region->color; |
368 | 391 | ||
369 | if (info->state != FBINFO_STATE_RUNNING) | 392 | if (info->state != FBINFO_STATE_RUNNING) |
370 | return; | 393 | return; |
371 | if ((info->flags & FBINFO_HWACCEL_DISABLED) || | 394 | if (info->flags & FBINFO_HWACCEL_DISABLED) { |
372 | region->rop != ROP_COPY ) { | ||
373 | cfb_fillrect(info, region); | 395 | cfb_fillrect(info, region); |
374 | return; | 396 | return; |
375 | } | 397 | } |
398 | if (region->rop == ROP_COPY ) | ||
399 | rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */ | ||
400 | else | ||
401 | rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */ | ||
402 | PM3Config2D_FBDestReadEnable; | ||
376 | 403 | ||
377 | vxres = info->var.xres_virtual; | 404 | vxres = info->var.xres_virtual; |
378 | vyres = info->var.yres_virtual; | 405 | vyres = info->var.yres_virtual; |
379 | 406 | ||
380 | memcpy(&modded, region, sizeof(struct fb_fillrect)); | 407 | memcpy(&modded, region, sizeof(struct fb_fillrect)); |
381 | 408 | ||
382 | if(!modded.width || !modded.height || | 409 | if (!modded.width || !modded.height || |
383 | modded.dx >= vxres || modded.dy >= vyres) | 410 | modded.dx >= vxres || modded.dy >= vyres) |
384 | return; | 411 | return; |
385 | 412 | ||
386 | if(modded.dx + modded.width > vxres) | 413 | if (modded.dx + modded.width > vxres) |
387 | modded.width = vxres - modded.dx; | 414 | modded.width = vxres - modded.dx; |
388 | if(modded.dy + modded.height > vyres) | 415 | if (modded.dy + modded.height > vyres) |
389 | modded.height = vyres - modded.dy; | 416 | modded.height = vyres - modded.dy; |
390 | 417 | ||
391 | if(info->var.bits_per_pixel == 8) | 418 | if (info->var.bits_per_pixel == 8) |
392 | color |= color << 8; | 419 | color |= color << 8; |
393 | if(info->var.bits_per_pixel <= 16) | 420 | if (info->var.bits_per_pixel <= 16) |
394 | color |= color << 16; | 421 | color |= color << 16; |
395 | 422 | ||
396 | PM3_WAIT(par, 4); | 423 | PM3_WAIT(par, 4); |
397 | 424 | /* ROP Ox3 is GXcopy */ | |
398 | PM3_WRITE_REG(par, PM3Config2D, | 425 | PM3_WRITE_REG(par, PM3Config2D, |
399 | PM3Config2D_UseConstantSource | | 426 | PM3Config2D_UseConstantSource | |
400 | PM3Config2D_ForegroundROPEnable | | 427 | PM3Config2D_ForegroundROPEnable | |
401 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | 428 | rop | |
402 | PM3Config2D_FBWriteEnable); | 429 | PM3Config2D_FBWriteEnable); |
403 | 430 | ||
404 | PM3_WRITE_REG(par, PM3ForegroundColor, color); | 431 | PM3_WRITE_REG(par, PM3ForegroundColor, color); |
405 | 432 | ||
406 | PM3_WRITE_REG(par, PM3RectanglePosition, | 433 | PM3_WRITE_REG(par, PM3RectanglePosition, |
407 | (PM3RectanglePosition_XOffset(modded.dx)) | | 434 | PM3RectanglePosition_XOffset(modded.dx) | |
408 | (PM3RectanglePosition_YOffset(modded.dy))); | 435 | PM3RectanglePosition_YOffset(modded.dy)); |
409 | 436 | ||
410 | PM3_WRITE_REG(par, PM3Render2D, | 437 | PM3_WRITE_REG(par, PM3Render2D, |
411 | PM3Render2D_XPositive | | 438 | PM3Render2D_XPositive | |
412 | PM3Render2D_YPositive | | 439 | PM3Render2D_YPositive | |
413 | PM3Render2D_Operation_Normal | | 440 | PM3Render2D_Operation_Normal | |
414 | PM3Render2D_SpanOperation | | 441 | PM3Render2D_SpanOperation | |
415 | (PM3Render2D_Width(modded.width)) | | 442 | PM3Render2D_Width(modded.width) | |
416 | (PM3Render2D_Height(modded.height))); | 443 | PM3Render2D_Height(modded.height)); |
444 | } | ||
445 | |||
446 | static void pm3fb_copyarea(struct fb_info *info, | ||
447 | const struct fb_copyarea *area) | ||
448 | { | ||
449 | struct pm3_par *par = info->par; | ||
450 | struct fb_copyarea modded; | ||
451 | u32 vxres, vyres; | ||
452 | int x_align, o_x, o_y; | ||
453 | |||
454 | if (info->state != FBINFO_STATE_RUNNING) | ||
455 | return; | ||
456 | if (info->flags & FBINFO_HWACCEL_DISABLED) { | ||
457 | cfb_copyarea(info, area); | ||
458 | return; | ||
459 | } | ||
460 | |||
461 | memcpy(&modded, area, sizeof(struct fb_copyarea)); | ||
462 | |||
463 | vxres = info->var.xres_virtual; | ||
464 | vyres = info->var.yres_virtual; | ||
465 | |||
466 | if (!modded.width || !modded.height || | ||
467 | modded.sx >= vxres || modded.sy >= vyres || | ||
468 | modded.dx >= vxres || modded.dy >= vyres) | ||
469 | return; | ||
470 | |||
471 | if (modded.sx + modded.width > vxres) | ||
472 | modded.width = vxres - modded.sx; | ||
473 | if (modded.dx + modded.width > vxres) | ||
474 | modded.width = vxres - modded.dx; | ||
475 | if (modded.sy + modded.height > vyres) | ||
476 | modded.height = vyres - modded.sy; | ||
477 | if (modded.dy + modded.height > vyres) | ||
478 | modded.height = vyres - modded.dy; | ||
479 | |||
480 | o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ | ||
481 | o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ | ||
482 | |||
483 | x_align = (modded.sx & 0x1f); | ||
484 | |||
485 | PM3_WAIT(par, 6); | ||
486 | |||
487 | PM3_WRITE_REG(par, PM3Config2D, | ||
488 | PM3Config2D_UserScissorEnable | | ||
489 | PM3Config2D_ForegroundROPEnable | | ||
490 | PM3Config2D_Blocking | | ||
491 | PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */ | ||
492 | PM3Config2D_FBWriteEnable); | ||
493 | |||
494 | PM3_WRITE_REG(par, PM3ScissorMinXY, | ||
495 | ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); | ||
496 | PM3_WRITE_REG(par, PM3ScissorMaxXY, | ||
497 | (((modded.dy + modded.height) & 0x0fff) << 16) | | ||
498 | ((modded.dx + modded.width) & 0x0fff)); | ||
499 | |||
500 | PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, | ||
501 | PM3FBSourceReadBufferOffset_XOffset(o_x) | | ||
502 | PM3FBSourceReadBufferOffset_YOffset(o_y)); | ||
503 | |||
504 | PM3_WRITE_REG(par, PM3RectanglePosition, | ||
505 | PM3RectanglePosition_XOffset(modded.dx - x_align) | | ||
506 | PM3RectanglePosition_YOffset(modded.dy)); | ||
507 | |||
508 | PM3_WRITE_REG(par, PM3Render2D, | ||
509 | ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | | ||
510 | ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | | ||
511 | PM3Render2D_Operation_Normal | | ||
512 | PM3Render2D_SpanOperation | | ||
513 | PM3Render2D_FBSourceReadEnable | | ||
514 | PM3Render2D_Width(modded.width + x_align) | | ||
515 | PM3Render2D_Height(modded.height)); | ||
516 | } | ||
517 | |||
518 | static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
519 | { | ||
520 | struct pm3_par *par = info->par; | ||
521 | u32 height = image->height; | ||
522 | u32 fgx, bgx; | ||
523 | const u32 *src = (const u32 *)image->data; | ||
524 | |||
525 | if (info->state != FBINFO_STATE_RUNNING) | ||
526 | return; | ||
527 | if (info->flags & FBINFO_HWACCEL_DISABLED) { | ||
528 | cfb_imageblit(info, image); | ||
529 | return; | ||
530 | } | ||
531 | switch (info->fix.visual) { | ||
532 | case FB_VISUAL_PSEUDOCOLOR: | ||
533 | fgx = image->fg_color; | ||
534 | bgx = image->bg_color; | ||
535 | break; | ||
536 | case FB_VISUAL_TRUECOLOR: | ||
537 | default: | ||
538 | fgx = par->palette[image->fg_color]; | ||
539 | bgx = par->palette[image->bg_color]; | ||
540 | break; | ||
541 | } | ||
542 | if (image->depth != 1) | ||
543 | return cfb_imageblit(info, image); | ||
544 | |||
545 | if (info->var.bits_per_pixel == 8) { | ||
546 | fgx |= fgx << 8; | ||
547 | bgx |= bgx << 8; | ||
548 | } | ||
549 | if (info->var.bits_per_pixel <= 16) { | ||
550 | fgx |= fgx << 16; | ||
551 | bgx |= bgx << 16; | ||
552 | } | ||
553 | |||
554 | PM3_WAIT(par, 7); | ||
555 | |||
556 | PM3_WRITE_REG(par, PM3ForegroundColor, fgx); | ||
557 | PM3_WRITE_REG(par, PM3BackgroundColor, bgx); | ||
558 | |||
559 | /* ROP Ox3 is GXcopy */ | ||
560 | PM3_WRITE_REG(par, PM3Config2D, | ||
561 | PM3Config2D_UserScissorEnable | | ||
562 | PM3Config2D_UseConstantSource | | ||
563 | PM3Config2D_ForegroundROPEnable | | ||
564 | PM3Config2D_ForegroundROP(0x3) | | ||
565 | PM3Config2D_OpaqueSpan | | ||
566 | PM3Config2D_FBWriteEnable); | ||
567 | PM3_WRITE_REG(par, PM3ScissorMinXY, | ||
568 | ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff)); | ||
569 | PM3_WRITE_REG(par, PM3ScissorMaxXY, | ||
570 | (((image->dy + image->height) & 0x0fff) << 16) | | ||
571 | ((image->dx + image->width) & 0x0fff)); | ||
572 | PM3_WRITE_REG(par, PM3RectanglePosition, | ||
573 | PM3RectanglePosition_XOffset(image->dx) | | ||
574 | PM3RectanglePosition_YOffset(image->dy)); | ||
575 | PM3_WRITE_REG(par, PM3Render2D, | ||
576 | PM3Render2D_XPositive | | ||
577 | PM3Render2D_YPositive | | ||
578 | PM3Render2D_Operation_SyncOnBitMask | | ||
579 | PM3Render2D_SpanOperation | | ||
580 | PM3Render2D_Width(image->width) | | ||
581 | PM3Render2D_Height(image->height)); | ||
582 | |||
583 | |||
584 | while (height--) { | ||
585 | int width = ((image->width + 7) >> 3) | ||
586 | + info->pixmap.scan_align - 1; | ||
587 | width >>= 2; | ||
588 | |||
589 | while (width >= PM3_FIFO_SIZE) { | ||
590 | int i = PM3_FIFO_SIZE - 1; | ||
591 | |||
592 | PM3_WAIT(par, PM3_FIFO_SIZE); | ||
593 | while (i--) { | ||
594 | PM3_WRITE_REG(par, PM3BitMaskPattern, *src); | ||
595 | src++; | ||
596 | } | ||
597 | width -= PM3_FIFO_SIZE - 1; | ||
598 | } | ||
599 | |||
600 | PM3_WAIT(par, width + 1); | ||
601 | while (width--) { | ||
602 | PM3_WRITE_REG(par, PM3BitMaskPattern, *src); | ||
603 | src++; | ||
604 | } | ||
605 | } | ||
417 | } | 606 | } |
418 | /* end of acceleration functions */ | 607 | /* end of acceleration functions */ |
419 | 608 | ||
609 | /* | ||
610 | * Hardware Cursor support. | ||
611 | */ | ||
612 | static const u8 cursor_bits_lookup[16] = { | ||
613 | 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, | ||
614 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 | ||
615 | }; | ||
616 | |||
617 | static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
618 | { | ||
619 | struct pm3_par *par = info->par; | ||
620 | u8 mode; | ||
621 | |||
622 | if (!hwcursor) | ||
623 | return -EINVAL; /* just to force soft_cursor() call */ | ||
624 | |||
625 | /* Too large of a cursor or wrong bpp :-( */ | ||
626 | if (cursor->image.width > 64 || | ||
627 | cursor->image.height > 64 || | ||
628 | cursor->image.depth > 1) | ||
629 | return -EINVAL; | ||
630 | |||
631 | mode = PM3RD_CursorMode_TYPE_X; | ||
632 | if (cursor->enable) | ||
633 | mode |= PM3RD_CursorMode_CURSOR_ENABLE; | ||
634 | |||
635 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode); | ||
636 | |||
637 | /* | ||
638 | * If the cursor is not be changed this means either we want the | ||
639 | * current cursor state (if enable is set) or we want to query what | ||
640 | * we can do with the cursor (if enable is not set) | ||
641 | */ | ||
642 | if (!cursor->set) | ||
643 | return 0; | ||
644 | |||
645 | if (cursor->set & FB_CUR_SETPOS) { | ||
646 | int x = cursor->image.dx - info->var.xoffset; | ||
647 | int y = cursor->image.dy - info->var.yoffset; | ||
648 | |||
649 | PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff); | ||
650 | PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf); | ||
651 | PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff); | ||
652 | PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf); | ||
653 | } | ||
654 | |||
655 | if (cursor->set & FB_CUR_SETHOT) { | ||
656 | PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX, | ||
657 | cursor->hot.x & 0x3f); | ||
658 | PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY, | ||
659 | cursor->hot.y & 0x3f); | ||
660 | } | ||
661 | |||
662 | if (cursor->set & FB_CUR_SETCMAP) { | ||
663 | u32 fg_idx = cursor->image.fg_color; | ||
664 | u32 bg_idx = cursor->image.bg_color; | ||
665 | struct fb_cmap cmap = info->cmap; | ||
666 | |||
667 | /* the X11 driver says one should use these color registers */ | ||
668 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39), | ||
669 | cmap.red[fg_idx] >> 8 ); | ||
670 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40), | ||
671 | cmap.green[fg_idx] >> 8 ); | ||
672 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41), | ||
673 | cmap.blue[fg_idx] >> 8 ); | ||
674 | |||
675 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42), | ||
676 | cmap.red[bg_idx] >> 8 ); | ||
677 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43), | ||
678 | cmap.green[bg_idx] >> 8 ); | ||
679 | PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44), | ||
680 | cmap.blue[bg_idx] >> 8 ); | ||
681 | } | ||
682 | |||
683 | if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { | ||
684 | u8 *bitmap = (u8 *)cursor->image.data; | ||
685 | u8 *mask = (u8 *)cursor->mask; | ||
686 | int i; | ||
687 | int pos = PM3RD_CursorPattern(0); | ||
688 | |||
689 | for (i = 0; i < cursor->image.height; i++) { | ||
690 | int j = (cursor->image.width + 7) >> 3; | ||
691 | int k = 8 - j; | ||
692 | |||
693 | for (; j > 0; j--) { | ||
694 | u8 data = *bitmap ^ *mask; | ||
695 | |||
696 | if (cursor->rop == ROP_COPY) | ||
697 | data = *mask & *bitmap; | ||
698 | /* Upper 4 bits of bitmap data */ | ||
699 | PM3_WRITE_DAC_REG(par, pos++, | ||
700 | cursor_bits_lookup[data >> 4] | | ||
701 | (cursor_bits_lookup[*mask >> 4] << 1)); | ||
702 | /* Lower 4 bits of bitmap */ | ||
703 | PM3_WRITE_DAC_REG(par, pos++, | ||
704 | cursor_bits_lookup[data & 0xf] | | ||
705 | (cursor_bits_lookup[*mask & 0xf] << 1)); | ||
706 | bitmap++; | ||
707 | mask++; | ||
708 | } | ||
709 | for (; k > 0; k--) { | ||
710 | PM3_WRITE_DAC_REG(par, pos++, 0); | ||
711 | PM3_WRITE_DAC_REG(par, pos++, 0); | ||
712 | } | ||
713 | } | ||
714 | while (pos < PM3RD_CursorPattern(1024)) | ||
715 | PM3_WRITE_DAC_REG(par, pos++, 0); | ||
716 | } | ||
717 | return 0; | ||
718 | } | ||
719 | |||
420 | /* write the mode to registers */ | 720 | /* write the mode to registers */ |
421 | static void pm3fb_write_mode(struct fb_info *info) | 721 | static void pm3fb_write_mode(struct fb_info *info) |
422 | { | 722 | { |
423 | struct pm3_par *par = info->par; | 723 | struct pm3_par *par = info->par; |
424 | char tempsync = 0x00, tempmisc = 0x00; | 724 | char tempsync = 0x00; |
725 | char tempmisc = 0x00; | ||
425 | const u32 hsstart = info->var.right_margin; | 726 | const u32 hsstart = info->var.right_margin; |
426 | const u32 hsend = hsstart + info->var.hsync_len; | 727 | const u32 hsend = hsstart + info->var.hsync_len; |
427 | const u32 hbend = hsend + info->var.left_margin; | 728 | const u32 hbend = hsend + info->var.left_margin; |
@@ -618,47 +919,57 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
618 | unsigned bpp = var->red.length + var->green.length | 919 | unsigned bpp = var->red.length + var->green.length |
619 | + var->blue.length + var->transp.length; | 920 | + var->blue.length + var->transp.length; |
620 | 921 | ||
621 | if ( bpp != var->bits_per_pixel ) { | 922 | if (bpp != var->bits_per_pixel) { |
622 | /* set predefined mode for bits_per_pixel settings */ | 923 | /* set predefined mode for bits_per_pixel settings */ |
623 | 924 | ||
624 | switch(var->bits_per_pixel) { | 925 | switch (var->bits_per_pixel) { |
625 | case 8: | 926 | case 8: |
626 | var->red.length = var->green.length = var->blue.length = 8; | 927 | var->red.length = 8; |
627 | var->red.offset = var->green.offset = var->blue.offset = 0; | 928 | var->green.length = 8; |
929 | var->blue.length = 8; | ||
930 | var->red.offset = 0; | ||
931 | var->green.offset = 0; | ||
932 | var->blue.offset = 0; | ||
628 | var->transp.offset = 0; | 933 | var->transp.offset = 0; |
629 | var->transp.length = 0; | 934 | var->transp.length = 0; |
630 | break; | 935 | break; |
631 | case 16: | 936 | case 16: |
632 | var->red.length = var->blue.length = 5; | 937 | var->red.length = 5; |
938 | var->blue.length = 5; | ||
633 | var->green.length = 6; | 939 | var->green.length = 6; |
634 | var->transp.length = 0; | 940 | var->transp.length = 0; |
635 | break; | 941 | break; |
636 | case 32: | 942 | case 32: |
637 | var->red.length = var->green.length = var->blue.length = 8; | 943 | var->red.length = 8; |
944 | var->green.length = 8; | ||
945 | var->blue.length = 8; | ||
638 | var->transp.length = 8; | 946 | var->transp.length = 8; |
639 | break; | 947 | break; |
640 | default: | 948 | default: |
641 | DPRINTK("depth not supported: %u\n", var->bits_per_pixel); | 949 | DPRINTK("depth not supported: %u\n", |
950 | var->bits_per_pixel); | ||
642 | return -EINVAL; | 951 | return -EINVAL; |
643 | } | 952 | } |
644 | } | 953 | } |
645 | /* it is assumed BGRA order */ | 954 | /* it is assumed BGRA order */ |
646 | if (var->bits_per_pixel > 8 ) | 955 | if (var->bits_per_pixel > 8 ) { |
647 | { | ||
648 | var->blue.offset = 0; | 956 | var->blue.offset = 0; |
649 | var->green.offset = var->blue.length; | 957 | var->green.offset = var->blue.length; |
650 | var->red.offset = var->green.offset + var->green.length; | 958 | var->red.offset = var->green.offset + var->green.length; |
651 | var->transp.offset = var->red.offset + var->red.length; | 959 | var->transp.offset = var->red.offset + var->red.length; |
652 | } | 960 | } |
653 | var->height = var->width = -1; | 961 | var->height = -1; |
962 | var->width = -1; | ||
654 | 963 | ||
655 | if (var->xres != var->xres_virtual) { | 964 | if (var->xres != var->xres_virtual) { |
656 | DPRINTK("virtual x resolution != physical x resolution not supported\n"); | 965 | DPRINTK("virtual x resolution != " |
966 | "physical x resolution not supported\n"); | ||
657 | return -EINVAL; | 967 | return -EINVAL; |
658 | } | 968 | } |
659 | 969 | ||
660 | if (var->yres > var->yres_virtual) { | 970 | if (var->yres > var->yres_virtual) { |
661 | DPRINTK("virtual y resolution < physical y resolution not possible\n"); | 971 | DPRINTK("virtual y resolution < " |
972 | "physical y resolution not possible\n"); | ||
662 | return -EINVAL; | 973 | return -EINVAL; |
663 | } | 974 | } |
664 | 975 | ||
@@ -673,7 +984,7 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
673 | } | 984 | } |
674 | 985 | ||
675 | var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ | 986 | var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ |
676 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); | 987 | lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); |
677 | 988 | ||
678 | if (var->xres < 200 || var->xres > 2048) { | 989 | if (var->xres < 200 || var->xres > 2048) { |
679 | DPRINTK("width not supported: %u\n", var->xres); | 990 | DPRINTK("width not supported: %u\n", var->xres); |
@@ -692,7 +1003,8 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
692 | } | 1003 | } |
693 | 1004 | ||
694 | if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { | 1005 | if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { |
695 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); | 1006 | DPRINTK("pixclock too high (%ldKHz)\n", |
1007 | PICOS2KHZ(var->pixclock)); | ||
696 | return -EINVAL; | 1008 | return -EINVAL; |
697 | } | 1009 | } |
698 | 1010 | ||
@@ -709,7 +1021,7 @@ static int pm3fb_set_par(struct fb_info *info) | |||
709 | const u32 xres = (info->var.xres + 31) & ~31; | 1021 | const u32 xres = (info->var.xres + 31) & ~31; |
710 | const unsigned bpp = info->var.bits_per_pixel; | 1022 | const unsigned bpp = info->var.bits_per_pixel; |
711 | 1023 | ||
712 | par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) | 1024 | par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres) |
713 | + info->var.xoffset); | 1025 | + info->var.xoffset); |
714 | par->video = 0; | 1026 | par->video = 0; |
715 | 1027 | ||
@@ -725,15 +1037,12 @@ static int pm3fb_set_par(struct fb_info *info) | |||
725 | 1037 | ||
726 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) | 1038 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) |
727 | par->video |= PM3VideoControl_LINE_DOUBLE_ON; | 1039 | par->video |= PM3VideoControl_LINE_DOUBLE_ON; |
728 | else | ||
729 | par->video |= PM3VideoControl_LINE_DOUBLE_OFF; | ||
730 | 1040 | ||
731 | if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) | 1041 | if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) |
732 | par->video |= PM3VideoControl_ENABLE; | 1042 | par->video |= PM3VideoControl_ENABLE; |
733 | else { | 1043 | else |
734 | par->video |= PM3VideoControl_DISABLE; | ||
735 | DPRINTK("PM3Video disabled\n"); | 1044 | DPRINTK("PM3Video disabled\n"); |
736 | } | 1045 | |
737 | switch (bpp) { | 1046 | switch (bpp) { |
738 | case 8: | 1047 | case 8: |
739 | par->video |= PM3VideoControl_PIXELSIZE_8BIT; | 1048 | par->video |= PM3VideoControl_PIXELSIZE_8BIT; |
@@ -751,13 +1060,11 @@ static int pm3fb_set_par(struct fb_info *info) | |||
751 | 1060 | ||
752 | info->fix.visual = | 1061 | info->fix.visual = |
753 | (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | 1062 | (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
754 | info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) | 1063 | info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp; |
755 | * bpp / 8; | ||
756 | 1064 | ||
757 | /* pm3fb_clear_memory(info, 0);*/ | 1065 | /* pm3fb_clear_memory(info, 0);*/ |
758 | pm3fb_clear_colormap(par, 0, 0, 0); | 1066 | pm3fb_clear_colormap(par, 0, 0, 0); |
759 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, | 1067 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0); |
760 | PM3RD_CursorMode_CURSOR_DISABLE); | ||
761 | pm3fb_init_engine(info); | 1068 | pm3fb_init_engine(info); |
762 | pm3fb_write_mode(info); | 1069 | pm3fb_write_mode(info); |
763 | return 0; | 1070 | return 0; |
@@ -773,10 +1080,9 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
773 | return -EINVAL; | 1080 | return -EINVAL; |
774 | 1081 | ||
775 | /* grayscale works only partially under directcolor */ | 1082 | /* grayscale works only partially under directcolor */ |
776 | if (info->var.grayscale) { | 1083 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ |
777 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | 1084 | if (info->var.grayscale) |
778 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | 1085 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; |
779 | } | ||
780 | 1086 | ||
781 | /* Directcolor: | 1087 | /* Directcolor: |
782 | * var->{color}.offset contains start of bitfield | 1088 | * var->{color}.offset contains start of bitfield |
@@ -790,8 +1096,8 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
790 | * | 1096 | * |
791 | * Pseudocolor: | 1097 | * Pseudocolor: |
792 | * var->{color}.offset is 0 | 1098 | * var->{color}.offset is 0 |
793 | * var->{color}.length contains width of DAC or the number of unique | 1099 | * var->{color}.length contains width of DAC or the number |
794 | * colors available (color depth) | 1100 | * of unique colors available (color depth) |
795 | * pseudo_palette is not used | 1101 | * pseudo_palette is not used |
796 | * RAMDAC[X] is programmed to (red, green, blue) | 1102 | * RAMDAC[X] is programmed to (red, green, blue) |
797 | * color depth = var->{color}.length | 1103 | * color depth = var->{color}.length |
@@ -801,7 +1107,7 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
801 | * This is the point where the color is converted to something that | 1107 | * This is the point where the color is converted to something that |
802 | * is acceptable by the hardware. | 1108 | * is acceptable by the hardware. |
803 | */ | 1109 | */ |
804 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 1110 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) |
805 | red = CNVT_TOHW(red, info->var.red.length); | 1111 | red = CNVT_TOHW(red, info->var.red.length); |
806 | green = CNVT_TOHW(green, info->var.green.length); | 1112 | green = CNVT_TOHW(green, info->var.green.length); |
807 | blue = CNVT_TOHW(blue, info->var.blue.length); | 1113 | blue = CNVT_TOHW(blue, info->var.blue.length); |
@@ -825,12 +1131,11 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
825 | break; | 1131 | break; |
826 | case 16: | 1132 | case 16: |
827 | case 32: | 1133 | case 32: |
828 | ((u32*)(info->pseudo_palette))[regno] = v; | 1134 | ((u32 *)(info->pseudo_palette))[regno] = v; |
829 | break; | 1135 | break; |
830 | } | 1136 | } |
831 | return 0; | 1137 | return 0; |
832 | } | 1138 | } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) |
833 | else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) | ||
834 | pm3fb_set_color(par, regno, red, green, blue); | 1139 | pm3fb_set_color(par, regno, red, green, blue); |
835 | 1140 | ||
836 | return 0; | 1141 | return 0; |
@@ -871,7 +1176,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info) | |||
871 | video |= PM3VideoControl_ENABLE; | 1176 | video |= PM3VideoControl_ENABLE; |
872 | break; | 1177 | break; |
873 | case FB_BLANK_NORMAL: | 1178 | case FB_BLANK_NORMAL: |
874 | video &= ~(PM3VideoControl_ENABLE); | 1179 | video &= ~PM3VideoControl_ENABLE; |
875 | break; | 1180 | break; |
876 | case FB_BLANK_HSYNC_SUSPEND: | 1181 | case FB_BLANK_HSYNC_SUSPEND: |
877 | video &= ~(PM3VideoControl_HSYNC_MASK | | 1182 | video &= ~(PM3VideoControl_HSYNC_MASK | |
@@ -892,7 +1197,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info) | |||
892 | } | 1197 | } |
893 | 1198 | ||
894 | PM3_WAIT(par, 1); | 1199 | PM3_WAIT(par, 1); |
895 | PM3_WRITE_REG(par,PM3VideoControl, video); | 1200 | PM3_WRITE_REG(par, PM3VideoControl, video); |
896 | return 0; | 1201 | return 0; |
897 | } | 1202 | } |
898 | 1203 | ||
@@ -907,10 +1212,11 @@ static struct fb_ops pm3fb_ops = { | |||
907 | .fb_setcolreg = pm3fb_setcolreg, | 1212 | .fb_setcolreg = pm3fb_setcolreg, |
908 | .fb_pan_display = pm3fb_pan_display, | 1213 | .fb_pan_display = pm3fb_pan_display, |
909 | .fb_fillrect = pm3fb_fillrect, | 1214 | .fb_fillrect = pm3fb_fillrect, |
910 | .fb_copyarea = cfb_copyarea, | 1215 | .fb_copyarea = pm3fb_copyarea, |
911 | .fb_imageblit = cfb_imageblit, | 1216 | .fb_imageblit = pm3fb_imageblit, |
912 | .fb_blank = pm3fb_blank, | 1217 | .fb_blank = pm3fb_blank, |
913 | .fb_sync = pm3fb_sync, | 1218 | .fb_sync = pm3fb_sync, |
1219 | .fb_cursor = pm3fb_cursor, | ||
914 | }; | 1220 | }; |
915 | 1221 | ||
916 | /* ------------------------------------------------------------------------- */ | 1222 | /* ------------------------------------------------------------------------- */ |
@@ -923,7 +1229,8 @@ static struct fb_ops pm3fb_ops = { | |||
923 | /* the pm3fb_fix.smem_start is also set */ | 1229 | /* the pm3fb_fix.smem_start is also set */ |
924 | static unsigned long pm3fb_size_memory(struct pm3_par *par) | 1230 | static unsigned long pm3fb_size_memory(struct pm3_par *par) |
925 | { | 1231 | { |
926 | unsigned long memsize = 0, tempBypass, i, temp1, temp2; | 1232 | unsigned long memsize = 0; |
1233 | unsigned long tempBypass, i, temp1, temp2; | ||
927 | unsigned char __iomem *screen_mem; | 1234 | unsigned char __iomem *screen_mem; |
928 | 1235 | ||
929 | pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ | 1236 | pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ |
@@ -951,7 +1258,9 @@ static unsigned long pm3fb_size_memory(struct pm3_par *par) | |||
951 | PM3_WAIT(par, 1); | 1258 | PM3_WAIT(par, 1); |
952 | PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); | 1259 | PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); |
953 | 1260 | ||
954 | /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ | 1261 | /* pm3 split up memory, replicates, and do a lot of |
1262 | * nasty stuff IMHO ;-) | ||
1263 | */ | ||
955 | for (i = 0; i < 32; i++) { | 1264 | for (i = 0; i < 32; i++) { |
956 | fb_writel(i * 0x00345678, | 1265 | fb_writel(i * 0x00345678, |
957 | (screen_mem + (i * 1048576))); | 1266 | (screen_mem + (i * 1048576))); |
@@ -1008,8 +1317,9 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1008 | { | 1317 | { |
1009 | struct fb_info *info; | 1318 | struct fb_info *info; |
1010 | struct pm3_par *par; | 1319 | struct pm3_par *par; |
1011 | struct device* device = &dev->dev; /* for pci drivers */ | 1320 | struct device *device = &dev->dev; /* for pci drivers */ |
1012 | int err, retval = -ENXIO; | 1321 | int err; |
1322 | int retval = -ENXIO; | ||
1013 | 1323 | ||
1014 | err = pci_enable_device(dev); | 1324 | err = pci_enable_device(dev); |
1015 | if (err) { | 1325 | if (err) { |
@@ -1031,6 +1341,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1031 | */ | 1341 | */ |
1032 | pm3fb_fix.mmio_start = pci_resource_start(dev, 0); | 1342 | pm3fb_fix.mmio_start = pci_resource_start(dev, 0); |
1033 | pm3fb_fix.mmio_len = PM3_REGS_SIZE; | 1343 | pm3fb_fix.mmio_len = PM3_REGS_SIZE; |
1344 | #if defined(__BIG_ENDIAN) | ||
1345 | pm3fb_fix.mmio_start += PM3_REGS_SIZE; | ||
1346 | DPRINTK("Adjusting register base for big-endian.\n"); | ||
1347 | #endif | ||
1034 | 1348 | ||
1035 | /* Registers - request region and map it. */ | 1349 | /* Registers - request region and map it. */ |
1036 | if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, | 1350 | if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, |
@@ -1047,15 +1361,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1047 | goto err_exit_neither; | 1361 | goto err_exit_neither; |
1048 | } | 1362 | } |
1049 | 1363 | ||
1050 | #if defined(__BIG_ENDIAN) | ||
1051 | pm3fb_fix.mmio_start += PM3_REGS_SIZE; | ||
1052 | DPRINTK("Adjusting register base for big-endian.\n"); | ||
1053 | #endif | ||
1054 | /* Linear frame buffer - request region and map it. */ | 1364 | /* Linear frame buffer - request region and map it. */ |
1055 | pm3fb_fix.smem_start = pci_resource_start(dev, 1); | 1365 | pm3fb_fix.smem_start = pci_resource_start(dev, 1); |
1056 | pm3fb_fix.smem_len = pm3fb_size_memory(par); | 1366 | pm3fb_fix.smem_len = pm3fb_size_memory(par); |
1057 | if (!pm3fb_fix.smem_len) | 1367 | if (!pm3fb_fix.smem_len) { |
1058 | { | ||
1059 | printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); | 1368 | printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); |
1060 | goto err_exit_mmio; | 1369 | goto err_exit_mmio; |
1061 | } | 1370 | } |
@@ -1073,6 +1382,12 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1073 | } | 1382 | } |
1074 | info->screen_size = pm3fb_fix.smem_len; | 1383 | info->screen_size = pm3fb_fix.smem_len; |
1075 | 1384 | ||
1385 | #ifdef CONFIG_MTRR | ||
1386 | if (!nomtrr) | ||
1387 | par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start, | ||
1388 | pm3fb_fix.smem_len, | ||
1389 | MTRR_TYPE_WRCOMB, 1); | ||
1390 | #endif | ||
1076 | info->fbops = &pm3fb_ops; | 1391 | info->fbops = &pm3fb_ops; |
1077 | 1392 | ||
1078 | par->video = PM3_READ_REG(par, PM3VideoControl); | 1393 | par->video = PM3_READ_REG(par, PM3VideoControl); |
@@ -1080,7 +1395,26 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1080 | info->fix = pm3fb_fix; | 1395 | info->fix = pm3fb_fix; |
1081 | info->pseudo_palette = par->palette; | 1396 | info->pseudo_palette = par->palette; |
1082 | info->flags = FBINFO_DEFAULT | | 1397 | info->flags = FBINFO_DEFAULT | |
1083 | FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ | 1398 | FBINFO_HWACCEL_XPAN | |
1399 | FBINFO_HWACCEL_YPAN | | ||
1400 | FBINFO_HWACCEL_COPYAREA | | ||
1401 | FBINFO_HWACCEL_IMAGEBLIT | | ||
1402 | FBINFO_HWACCEL_FILLRECT; | ||
1403 | |||
1404 | if (noaccel) { | ||
1405 | printk(KERN_DEBUG "disabling acceleration\n"); | ||
1406 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
1407 | } | ||
1408 | info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL); | ||
1409 | if (!info->pixmap.addr) { | ||
1410 | retval = -ENOMEM; | ||
1411 | goto err_exit_pixmap; | ||
1412 | } | ||
1413 | info->pixmap.size = PM3_PIXMAP_SIZE; | ||
1414 | info->pixmap.buf_align = 4; | ||
1415 | info->pixmap.scan_align = 4; | ||
1416 | info->pixmap.access_align = 32; | ||
1417 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
1084 | 1418 | ||
1085 | /* | 1419 | /* |
1086 | * This should give a reasonable default video mode. The following is | 1420 | * This should give a reasonable default video mode. The following is |
@@ -1118,6 +1452,8 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, | |||
1118 | err_exit_all: | 1452 | err_exit_all: |
1119 | fb_dealloc_cmap(&info->cmap); | 1453 | fb_dealloc_cmap(&info->cmap); |
1120 | err_exit_both: | 1454 | err_exit_both: |
1455 | kfree(info->pixmap.addr); | ||
1456 | err_exit_pixmap: | ||
1121 | iounmap(info->screen_base); | 1457 | iounmap(info->screen_base); |
1122 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | 1458 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); |
1123 | err_exit_mmio: | 1459 | err_exit_mmio: |
@@ -1142,12 +1478,18 @@ static void __devexit pm3fb_remove(struct pci_dev *dev) | |||
1142 | unregister_framebuffer(info); | 1478 | unregister_framebuffer(info); |
1143 | fb_dealloc_cmap(&info->cmap); | 1479 | fb_dealloc_cmap(&info->cmap); |
1144 | 1480 | ||
1481 | #ifdef CONFIG_MTRR | ||
1482 | if (par->mtrr_handle >= 0) | ||
1483 | mtrr_del(par->mtrr_handle, info->fix.smem_start, | ||
1484 | info->fix.smem_len); | ||
1485 | #endif /* CONFIG_MTRR */ | ||
1145 | iounmap(info->screen_base); | 1486 | iounmap(info->screen_base); |
1146 | release_mem_region(fix->smem_start, fix->smem_len); | 1487 | release_mem_region(fix->smem_start, fix->smem_len); |
1147 | iounmap(par->v_regs); | 1488 | iounmap(par->v_regs); |
1148 | release_mem_region(fix->mmio_start, fix->mmio_len); | 1489 | release_mem_region(fix->mmio_start, fix->mmio_len); |
1149 | 1490 | ||
1150 | pci_set_drvdata(dev, NULL); | 1491 | pci_set_drvdata(dev, NULL); |
1492 | kfree(info->pixmap.addr); | ||
1151 | framebuffer_release(info); | 1493 | framebuffer_release(info); |
1152 | } | 1494 | } |
1153 | } | 1495 | } |
@@ -1168,21 +1510,76 @@ static struct pci_driver pm3fb_driver = { | |||
1168 | 1510 | ||
1169 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); | 1511 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); |
1170 | 1512 | ||
1513 | #ifndef MODULE | ||
1514 | /* | ||
1515 | * Setup | ||
1516 | */ | ||
1517 | |||
1518 | /* | ||
1519 | * Only necessary if your driver takes special options, | ||
1520 | * otherwise we fall back on the generic fb_setup(). | ||
1521 | */ | ||
1522 | static int __init pm3fb_setup(char *options) | ||
1523 | { | ||
1524 | char *this_opt; | ||
1525 | |||
1526 | /* Parse user speficied options (`video=pm3fb:') */ | ||
1527 | if (!options || !*options) | ||
1528 | return 0; | ||
1529 | |||
1530 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
1531 | if (!*this_opt) | ||
1532 | continue; | ||
1533 | else if (!strncmp(this_opt, "noaccel", 7)) | ||
1534 | noaccel = 1; | ||
1535 | else if (!strncmp(this_opt, "hwcursor=", 9)) | ||
1536 | hwcursor = simple_strtoul(this_opt + 9, NULL, 0); | ||
1537 | #ifdef CONFIG_MTRR | ||
1538 | else if (!strncmp(this_opt, "nomtrr", 6)) | ||
1539 | nomtrr = 1; | ||
1540 | #endif | ||
1541 | else | ||
1542 | mode_option = this_opt; | ||
1543 | } | ||
1544 | return 0; | ||
1545 | } | ||
1546 | #endif /* MODULE */ | ||
1547 | |||
1171 | static int __init pm3fb_init(void) | 1548 | static int __init pm3fb_init(void) |
1172 | { | 1549 | { |
1550 | /* | ||
1551 | * For kernel boot options (in 'video=pm3fb:<options>' format) | ||
1552 | */ | ||
1173 | #ifndef MODULE | 1553 | #ifndef MODULE |
1174 | if (fb_get_options("pm3fb", NULL)) | 1554 | char *option = NULL; |
1555 | |||
1556 | if (fb_get_options("pm3fb", &option)) | ||
1175 | return -ENODEV; | 1557 | return -ENODEV; |
1558 | pm3fb_setup(option); | ||
1176 | #endif | 1559 | #endif |
1560 | |||
1177 | return pci_register_driver(&pm3fb_driver); | 1561 | return pci_register_driver(&pm3fb_driver); |
1178 | } | 1562 | } |
1179 | 1563 | ||
1564 | #ifdef MODULE | ||
1180 | static void __exit pm3fb_exit(void) | 1565 | static void __exit pm3fb_exit(void) |
1181 | { | 1566 | { |
1182 | pci_unregister_driver(&pm3fb_driver); | 1567 | pci_unregister_driver(&pm3fb_driver); |
1183 | } | 1568 | } |
1184 | 1569 | ||
1185 | module_init(pm3fb_init); | ||
1186 | module_exit(pm3fb_exit); | 1570 | module_exit(pm3fb_exit); |
1571 | #endif | ||
1572 | module_init(pm3fb_init); | ||
1573 | |||
1574 | module_param(noaccel, bool, 0); | ||
1575 | MODULE_PARM_DESC(noaccel, "Disable acceleration"); | ||
1576 | module_param(hwcursor, int, 0644); | ||
1577 | MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " | ||
1578 | "(1=enable, 0=disable, default=1)"); | ||
1579 | #ifdef CONFIG_MTRR | ||
1580 | module_param(nomtrr, bool, 0); | ||
1581 | MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); | ||
1582 | #endif | ||
1187 | 1583 | ||
1584 | MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); | ||
1188 | MODULE_LICENSE("GPL"); | 1585 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 264d37243fad..3a3f80f65219 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c | |||
@@ -147,16 +147,23 @@ static int __init pmagbafb_probe(struct device *dev) | |||
147 | resource_size_t start, len; | 147 | resource_size_t start, len; |
148 | struct fb_info *info; | 148 | struct fb_info *info; |
149 | struct pmagbafb_par *par; | 149 | struct pmagbafb_par *par; |
150 | int err; | ||
150 | 151 | ||
151 | info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev); | 152 | info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev); |
152 | if (!info) | 153 | if (!info) { |
154 | printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id); | ||
153 | return -ENOMEM; | 155 | return -ENOMEM; |
156 | } | ||
154 | 157 | ||
155 | par = info->par; | 158 | par = info->par; |
156 | dev_set_drvdata(dev, info); | 159 | dev_set_drvdata(dev, info); |
157 | 160 | ||
158 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) | 161 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
162 | printk(KERN_ERR "%s: Cannot allocate color map\n", | ||
163 | dev->bus_id); | ||
164 | err = -ENOMEM; | ||
159 | goto err_alloc; | 165 | goto err_alloc; |
166 | } | ||
160 | 167 | ||
161 | info->fbops = &pmagbafb_ops; | 168 | info->fbops = &pmagbafb_ops; |
162 | info->fix = pmagbafb_fix; | 169 | info->fix = pmagbafb_fix; |
@@ -166,28 +173,41 @@ static int __init pmagbafb_probe(struct device *dev) | |||
166 | /* Request the I/O MEM resource. */ | 173 | /* Request the I/O MEM resource. */ |
167 | start = tdev->resource.start; | 174 | start = tdev->resource.start; |
168 | len = tdev->resource.end - start + 1; | 175 | len = tdev->resource.end - start + 1; |
169 | if (!request_mem_region(start, len, dev->bus_id)) | 176 | if (!request_mem_region(start, len, dev->bus_id)) { |
177 | printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id); | ||
178 | err = -EBUSY; | ||
170 | goto err_cmap; | 179 | goto err_cmap; |
180 | } | ||
171 | 181 | ||
172 | /* MMIO mapping setup. */ | 182 | /* MMIO mapping setup. */ |
173 | info->fix.mmio_start = start; | 183 | info->fix.mmio_start = start; |
174 | par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); | 184 | par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); |
175 | if (!par->mmio) | 185 | if (!par->mmio) { |
186 | printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id); | ||
187 | err = -ENOMEM; | ||
176 | goto err_resource; | 188 | goto err_resource; |
189 | } | ||
177 | par->dac = par->mmio + PMAG_BA_BT459; | 190 | par->dac = par->mmio + PMAG_BA_BT459; |
178 | 191 | ||
179 | /* Frame buffer mapping setup. */ | 192 | /* Frame buffer mapping setup. */ |
180 | info->fix.smem_start = start + PMAG_BA_FBMEM; | 193 | info->fix.smem_start = start + PMAG_BA_FBMEM; |
181 | info->screen_base = ioremap_nocache(info->fix.smem_start, | 194 | info->screen_base = ioremap_nocache(info->fix.smem_start, |
182 | info->fix.smem_len); | 195 | info->fix.smem_len); |
183 | if (!info->screen_base) | 196 | if (!info->screen_base) { |
197 | printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id); | ||
198 | err = -ENOMEM; | ||
184 | goto err_mmio_map; | 199 | goto err_mmio_map; |
200 | } | ||
185 | info->screen_size = info->fix.smem_len; | 201 | info->screen_size = info->fix.smem_len; |
186 | 202 | ||
187 | pmagbafb_erase_cursor(info); | 203 | pmagbafb_erase_cursor(info); |
188 | 204 | ||
189 | if (register_framebuffer(info) < 0) | 205 | err = register_framebuffer(info); |
206 | if (err < 0) { | ||
207 | printk(KERN_ERR "%s: Cannot register framebuffer\n", | ||
208 | dev->bus_id); | ||
190 | goto err_smem_map; | 209 | goto err_smem_map; |
210 | } | ||
191 | 211 | ||
192 | get_device(dev); | 212 | get_device(dev); |
193 | 213 | ||
@@ -211,7 +231,7 @@ err_cmap: | |||
211 | 231 | ||
212 | err_alloc: | 232 | err_alloc: |
213 | framebuffer_release(info); | 233 | framebuffer_release(info); |
214 | return -ENXIO; | 234 | return err; |
215 | } | 235 | } |
216 | 236 | ||
217 | static int __exit pmagbafb_remove(struct device *dev) | 237 | static int __exit pmagbafb_remove(struct device *dev) |
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 7a0ce7d5af6b..9b80597241b0 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c | |||
@@ -254,16 +254,23 @@ static int __init pmagbbfb_probe(struct device *dev) | |||
254 | struct pmagbbfb_par *par; | 254 | struct pmagbbfb_par *par; |
255 | char freq0[12], freq1[12]; | 255 | char freq0[12], freq1[12]; |
256 | u32 vid_base; | 256 | u32 vid_base; |
257 | int err; | ||
257 | 258 | ||
258 | info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev); | 259 | info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev); |
259 | if (!info) | 260 | if (!info) { |
261 | printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id); | ||
260 | return -ENOMEM; | 262 | return -ENOMEM; |
263 | } | ||
261 | 264 | ||
262 | par = info->par; | 265 | par = info->par; |
263 | dev_set_drvdata(dev, info); | 266 | dev_set_drvdata(dev, info); |
264 | 267 | ||
265 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) | 268 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
269 | printk(KERN_ERR "%s: Cannot allocate color map\n", | ||
270 | dev->bus_id); | ||
271 | err = -ENOMEM; | ||
266 | goto err_alloc; | 272 | goto err_alloc; |
273 | } | ||
267 | 274 | ||
268 | info->fbops = &pmagbbfb_ops; | 275 | info->fbops = &pmagbbfb_ops; |
269 | info->fix = pmagbbfb_fix; | 276 | info->fix = pmagbbfb_fix; |
@@ -273,22 +280,31 @@ static int __init pmagbbfb_probe(struct device *dev) | |||
273 | /* Request the I/O MEM resource. */ | 280 | /* Request the I/O MEM resource. */ |
274 | start = tdev->resource.start; | 281 | start = tdev->resource.start; |
275 | len = tdev->resource.end - start + 1; | 282 | len = tdev->resource.end - start + 1; |
276 | if (!request_mem_region(start, len, dev->bus_id)) | 283 | if (!request_mem_region(start, len, dev->bus_id)) { |
284 | printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id); | ||
285 | err = -EBUSY; | ||
277 | goto err_cmap; | 286 | goto err_cmap; |
287 | } | ||
278 | 288 | ||
279 | /* MMIO mapping setup. */ | 289 | /* MMIO mapping setup. */ |
280 | info->fix.mmio_start = start; | 290 | info->fix.mmio_start = start; |
281 | par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); | 291 | par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); |
282 | if (!par->mmio) | 292 | if (!par->mmio) { |
293 | printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id); | ||
294 | err = -ENOMEM; | ||
283 | goto err_resource; | 295 | goto err_resource; |
296 | } | ||
284 | par->sfb = par->mmio + PMAGB_B_SFB; | 297 | par->sfb = par->mmio + PMAGB_B_SFB; |
285 | par->dac = par->mmio + PMAGB_B_BT459; | 298 | par->dac = par->mmio + PMAGB_B_BT459; |
286 | 299 | ||
287 | /* Frame buffer mapping setup. */ | 300 | /* Frame buffer mapping setup. */ |
288 | info->fix.smem_start = start + PMAGB_B_FBMEM; | 301 | info->fix.smem_start = start + PMAGB_B_FBMEM; |
289 | par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); | 302 | par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); |
290 | if (!par->smem) | 303 | if (!par->smem) { |
304 | printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id); | ||
305 | err = -ENOMEM; | ||
291 | goto err_mmio_map; | 306 | goto err_mmio_map; |
307 | } | ||
292 | vid_base = sfb_read(par, SFB_REG_VID_BASE); | 308 | vid_base = sfb_read(par, SFB_REG_VID_BASE); |
293 | info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000; | 309 | info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000; |
294 | info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000; | 310 | info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000; |
@@ -297,8 +313,12 @@ static int __init pmagbbfb_probe(struct device *dev) | |||
297 | pmagbbfb_screen_setup(info); | 313 | pmagbbfb_screen_setup(info); |
298 | pmagbbfb_osc_setup(info); | 314 | pmagbbfb_osc_setup(info); |
299 | 315 | ||
300 | if (register_framebuffer(info) < 0) | 316 | err = register_framebuffer(info); |
317 | if (err < 0) { | ||
318 | printk(KERN_ERR "%s: Cannot register framebuffer\n", | ||
319 | dev->bus_id); | ||
301 | goto err_smem_map; | 320 | goto err_smem_map; |
321 | } | ||
302 | 322 | ||
303 | get_device(dev); | 323 | get_device(dev); |
304 | 324 | ||
@@ -330,7 +350,7 @@ err_cmap: | |||
330 | 350 | ||
331 | err_alloc: | 351 | err_alloc: |
332 | framebuffer_release(info); | 352 | framebuffer_release(info); |
333 | return -ENXIO; | 353 | return err; |
334 | } | 354 | } |
335 | 355 | ||
336 | static int __exit pmagbbfb_remove(struct device *dev) | 356 | static int __exit pmagbbfb_remove(struct device *dev) |
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index f29e66e2d774..685761a0732c 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | 28 | ||
29 | #include <asm/uaccess.h> | ||
30 | #include "sdum.h" | 29 | #include "sdum.h" |
31 | #include "fbcommon.h" | 30 | #include "fbcommon.h" |
32 | 31 | ||
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 646ec823c168..b3463ddcfd60 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -22,22 +22,14 @@ | |||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/tty.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/vmalloc.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
30 | #include <linux/console.h> | 26 | #include <linux/console.h> |
31 | #include <linux/ioctl.h> | 27 | #include <linux/ioctl.h> |
32 | #include <linux/notifier.h> | ||
33 | #include <linux/reboot.h> | ||
34 | #include <linux/kthread.h> | 28 | #include <linux/kthread.h> |
35 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
36 | 30 | #include <linux/uaccess.h> | |
37 | #include <asm/uaccess.h> | ||
38 | #include <linux/fb.h> | 31 | #include <linux/fb.h> |
39 | #include <linux/init.h> | 32 | #include <linux/init.h> |
40 | #include <asm/time.h> | ||
41 | 33 | ||
42 | #include <asm/abs_addr.h> | 34 | #include <asm/abs_addr.h> |
43 | #include <asm/lv1call.h> | 35 | #include <asm/lv1call.h> |
@@ -48,12 +40,6 @@ | |||
48 | 40 | ||
49 | #define DEVICE_NAME "ps3fb" | 41 | #define DEVICE_NAME "ps3fb" |
50 | 42 | ||
51 | #ifdef PS3FB_DEBUG | ||
52 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) | ||
53 | #else | ||
54 | #define DPRINTK(fmt, args...) | ||
55 | #endif | ||
56 | |||
57 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 | 43 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 |
58 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 | 44 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 |
59 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 | 45 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 |
@@ -66,8 +52,10 @@ | |||
66 | #define L1GPU_DISPLAY_SYNC_VSYNC 2 | 52 | #define L1GPU_DISPLAY_SYNC_VSYNC 2 |
67 | 53 | ||
68 | #define DDR_SIZE (0) /* used no ddr */ | 54 | #define DDR_SIZE (0) /* used no ddr */ |
69 | #define GPU_OFFSET (64 * 1024) | 55 | #define GPU_CMD_BUF_SIZE (64 * 1024) |
70 | #define GPU_IOIF (0x0d000000UL) | 56 | #define GPU_IOIF (0x0d000000UL) |
57 | #define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64) | ||
58 | #define GPU_MAX_LINE_LENGTH (65536 - 64) | ||
71 | 59 | ||
72 | #define PS3FB_FULL_MODE_BIT 0x80 | 60 | #define PS3FB_FULL_MODE_BIT 0x80 |
73 | 61 | ||
@@ -131,13 +119,12 @@ struct ps3fb_priv { | |||
131 | 119 | ||
132 | u64 context_handle, memory_handle; | 120 | u64 context_handle, memory_handle; |
133 | void *xdr_ea; | 121 | void *xdr_ea; |
122 | size_t xdr_size; | ||
134 | struct gpu_driver_info *dinfo; | 123 | struct gpu_driver_info *dinfo; |
135 | u32 res_index; | ||
136 | 124 | ||
137 | u64 vblank_count; /* frame count */ | 125 | u64 vblank_count; /* frame count */ |
138 | wait_queue_head_t wait_vsync; | 126 | wait_queue_head_t wait_vsync; |
139 | 127 | ||
140 | u32 num_frames; /* num of frame buffers */ | ||
141 | atomic_t ext_flip; /* on/off flip with vsync */ | 128 | atomic_t ext_flip; /* on/off flip with vsync */ |
142 | atomic_t f_count; /* fb_open count */ | 129 | atomic_t f_count; /* fb_open count */ |
143 | int is_blanked; | 130 | int is_blanked; |
@@ -146,6 +133,18 @@ struct ps3fb_priv { | |||
146 | }; | 133 | }; |
147 | static struct ps3fb_priv ps3fb; | 134 | static struct ps3fb_priv ps3fb; |
148 | 135 | ||
136 | struct ps3fb_par { | ||
137 | u32 pseudo_palette[16]; | ||
138 | int mode_id, new_mode_id; | ||
139 | int res_index; | ||
140 | unsigned int num_frames; /* num of frame buffers */ | ||
141 | unsigned int width; | ||
142 | unsigned int height; | ||
143 | unsigned long full_offset; /* start of fullscreen DDR fb */ | ||
144 | unsigned long fb_offset; /* start of actual DDR fb */ | ||
145 | unsigned long pan_offset; | ||
146 | }; | ||
147 | |||
149 | struct ps3fb_res_table { | 148 | struct ps3fb_res_table { |
150 | u32 xres; | 149 | u32 xres; |
151 | u32 yres; | 150 | u32 yres; |
@@ -294,29 +293,31 @@ static const struct fb_videomode ps3fb_modedb[] = { | |||
294 | #define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */ | 293 | #define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */ |
295 | #define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */ | 294 | #define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */ |
296 | #define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */ | 295 | #define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */ |
297 | #define BPP 4 /* number of bytes per pixel */ | 296 | #define BPP 4 /* number of bytes per pixel */ |
298 | #define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP) | 297 | |
299 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) | 298 | /* Start of the virtual frame buffer (relative to fullscreen ) */ |
299 | #define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP) | ||
300 | |||
300 | 301 | ||
301 | static int ps3fb_mode; | 302 | static int ps3fb_mode; |
302 | module_param(ps3fb_mode, int, 0); | 303 | module_param(ps3fb_mode, int, 0); |
303 | 304 | ||
304 | static char *mode_option __devinitdata; | 305 | static char *mode_option __devinitdata; |
305 | 306 | ||
306 | static int ps3fb_get_res_table(u32 xres, u32 yres) | 307 | static int ps3fb_get_res_table(u32 xres, u32 yres, int mode) |
307 | { | 308 | { |
308 | int full_mode; | 309 | int full_mode; |
309 | unsigned int i; | 310 | unsigned int i; |
310 | u32 x, y, f; | 311 | u32 x, y, f; |
311 | 312 | ||
312 | full_mode = (ps3fb_mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; | 313 | full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; |
313 | for (i = 0;; i++) { | 314 | for (i = 0;; i++) { |
314 | x = ps3fb_res[i].xres; | 315 | x = ps3fb_res[i].xres; |
315 | y = ps3fb_res[i].yres; | 316 | y = ps3fb_res[i].yres; |
316 | f = ps3fb_res[i].type; | 317 | f = ps3fb_res[i].type; |
317 | 318 | ||
318 | if (!x) { | 319 | if (!x) { |
319 | DPRINTK("ERROR: ps3fb_get_res_table()\n"); | 320 | pr_debug("ERROR: ps3fb_get_res_table()\n"); |
320 | return -1; | 321 | return -1; |
321 | } | 322 | } |
322 | 323 | ||
@@ -335,7 +336,7 @@ static int ps3fb_get_res_table(u32 xres, u32 yres) | |||
335 | } | 336 | } |
336 | 337 | ||
337 | static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, | 338 | static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, |
338 | u32 *line_length) | 339 | u32 *ddr_line_length, u32 *xdr_line_length) |
339 | { | 340 | { |
340 | unsigned int i, mode; | 341 | unsigned int i, mode; |
341 | 342 | ||
@@ -350,31 +351,41 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, | |||
350 | var->upper_margin == ps3fb_modedb[i].upper_margin && | 351 | var->upper_margin == ps3fb_modedb[i].upper_margin && |
351 | var->lower_margin == ps3fb_modedb[i].lower_margin && | 352 | var->lower_margin == ps3fb_modedb[i].lower_margin && |
352 | var->sync == ps3fb_modedb[i].sync && | 353 | var->sync == ps3fb_modedb[i].sync && |
353 | (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) { | 354 | (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) |
354 | /* Cropped broadcast modes use the full line_length */ | 355 | goto found; |
355 | *line_length = | ||
356 | ps3fb_modedb[i < 10 ? i + 13 : i].xres * 4; | ||
357 | /* Full broadcast modes have the full mode bit set */ | ||
358 | mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; | ||
359 | |||
360 | DPRINTK("ps3fb_find_mode: mode %u\n", mode); | ||
361 | return mode; | ||
362 | } | ||
363 | 356 | ||
364 | DPRINTK("ps3fb_find_mode: mode not found\n"); | 357 | pr_debug("ps3fb_find_mode: mode not found\n"); |
365 | return 0; | 358 | return 0; |
366 | 359 | ||
360 | found: | ||
361 | /* Cropped broadcast modes use the full line length */ | ||
362 | *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP; | ||
363 | |||
364 | if (ps3_compare_firmware_version(1, 9, 0) >= 0) { | ||
365 | *xdr_line_length = GPU_ALIGN_UP(max(var->xres, | ||
366 | var->xres_virtual) * BPP); | ||
367 | if (*xdr_line_length > GPU_MAX_LINE_LENGTH) | ||
368 | *xdr_line_length = GPU_MAX_LINE_LENGTH; | ||
369 | } else | ||
370 | *xdr_line_length = *ddr_line_length; | ||
371 | |||
372 | /* Full broadcast modes have the full mode bit set */ | ||
373 | mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; | ||
374 | |||
375 | pr_debug("ps3fb_find_mode: mode %u\n", mode); | ||
376 | |||
377 | return mode; | ||
367 | } | 378 | } |
368 | 379 | ||
369 | static const struct fb_videomode *ps3fb_default_mode(void) | 380 | static const struct fb_videomode *ps3fb_default_mode(int id) |
370 | { | 381 | { |
371 | u32 mode = ps3fb_mode & PS3AV_MODE_MASK; | 382 | u32 mode = id & PS3AV_MODE_MASK; |
372 | u32 flags; | 383 | u32 flags; |
373 | 384 | ||
374 | if (mode < 1 || mode > 13) | 385 | if (mode < 1 || mode > 13) |
375 | return NULL; | 386 | return NULL; |
376 | 387 | ||
377 | flags = ps3fb_mode & ~PS3AV_MODE_MASK; | 388 | flags = id & ~PS3AV_MODE_MASK; |
378 | 389 | ||
379 | if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { | 390 | if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { |
380 | /* Full broadcast mode */ | 391 | /* Full broadcast mode */ |
@@ -384,55 +395,77 @@ static const struct fb_videomode *ps3fb_default_mode(void) | |||
384 | return &ps3fb_modedb[mode - 1]; | 395 | return &ps3fb_modedb[mode - 1]; |
385 | } | 396 | } |
386 | 397 | ||
387 | static int ps3fb_sync(u32 frame) | 398 | static void ps3fb_sync_image(struct device *dev, u64 frame_offset, |
399 | u64 dst_offset, u64 src_offset, u32 width, | ||
400 | u32 height, u32 dst_line_length, | ||
401 | u32 src_line_length) | ||
388 | { | 402 | { |
389 | int i, status; | 403 | int status; |
390 | u32 xres, yres; | 404 | u64 line_length; |
391 | u64 fb_ioif, offset; | ||
392 | |||
393 | i = ps3fb.res_index; | ||
394 | xres = ps3fb_res[i].xres; | ||
395 | yres = ps3fb_res[i].yres; | ||
396 | 405 | ||
397 | if (frame > ps3fb.num_frames - 1) { | 406 | line_length = dst_line_length; |
398 | printk(KERN_WARNING "%s: invalid frame number (%u)\n", | 407 | if (src_line_length != dst_line_length) |
399 | __func__, frame); | 408 | line_length |= (u64)src_line_length << 32; |
400 | return -EINVAL; | ||
401 | } | ||
402 | offset = xres * yres * BPP * frame; | ||
403 | 409 | ||
404 | fb_ioif = GPU_IOIF + FB_OFF(i) + offset; | ||
405 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 410 | status = lv1_gpu_context_attribute(ps3fb.context_handle, |
406 | L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, | 411 | L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, |
407 | offset, fb_ioif, | 412 | dst_offset, GPU_IOIF + src_offset, |
408 | L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | | 413 | L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | |
409 | (xres << 16) | yres, | 414 | (width << 16) | height, |
410 | xres * BPP); /* line_length */ | 415 | line_length); |
411 | if (status) | 416 | if (status) |
412 | printk(KERN_ERR | 417 | dev_err(dev, |
413 | "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", | 418 | "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", |
414 | __func__, status); | 419 | __func__, status); |
415 | #ifdef HEAD_A | 420 | #ifdef HEAD_A |
416 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 421 | status = lv1_gpu_context_attribute(ps3fb.context_handle, |
417 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, | 422 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, |
418 | 0, offset, 0, 0); | 423 | 0, frame_offset, 0, 0); |
419 | if (status) | 424 | if (status) |
420 | printk(KERN_ERR | 425 | dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", |
421 | "%s: lv1_gpu_context_attribute FLIP failed: %d\n", | 426 | __func__, status); |
422 | __func__, status); | ||
423 | #endif | 427 | #endif |
424 | #ifdef HEAD_B | 428 | #ifdef HEAD_B |
425 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 429 | status = lv1_gpu_context_attribute(ps3fb.context_handle, |
426 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, | 430 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, |
427 | 1, offset, 0, 0); | 431 | 1, frame_offset, 0, 0); |
428 | if (status) | 432 | if (status) |
429 | printk(KERN_ERR | 433 | dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", |
430 | "%s: lv1_gpu_context_attribute FLIP failed: %d\n", | 434 | __func__, status); |
431 | __func__, status); | ||
432 | #endif | 435 | #endif |
433 | return 0; | ||
434 | } | 436 | } |
435 | 437 | ||
438 | static int ps3fb_sync(struct fb_info *info, u32 frame) | ||
439 | { | ||
440 | struct ps3fb_par *par = info->par; | ||
441 | int i, error = 0; | ||
442 | u32 ddr_line_length, xdr_line_length; | ||
443 | u64 ddr_base, xdr_base; | ||
444 | |||
445 | acquire_console_sem(); | ||
446 | |||
447 | if (frame > par->num_frames - 1) { | ||
448 | dev_dbg(info->device, "%s: invalid frame number (%u)\n", | ||
449 | __func__, frame); | ||
450 | error = -EINVAL; | ||
451 | goto out; | ||
452 | } | ||
453 | |||
454 | i = par->res_index; | ||
455 | xdr_line_length = info->fix.line_length; | ||
456 | ddr_line_length = ps3fb_res[i].xres * BPP; | ||
457 | xdr_base = frame * info->var.yres_virtual * xdr_line_length; | ||
458 | ddr_base = frame * ps3fb_res[i].yres * ddr_line_length; | ||
459 | |||
460 | ps3fb_sync_image(info->device, ddr_base + par->full_offset, | ||
461 | ddr_base + par->fb_offset, xdr_base + par->pan_offset, | ||
462 | par->width, par->height, ddr_line_length, | ||
463 | xdr_line_length); | ||
464 | |||
465 | out: | ||
466 | release_console_sem(); | ||
467 | return error; | ||
468 | } | ||
436 | 469 | ||
437 | static int ps3fb_open(struct fb_info *info, int user) | 470 | static int ps3fb_open(struct fb_info *info, int user) |
438 | { | 471 | { |
@@ -445,7 +478,7 @@ static int ps3fb_release(struct fb_info *info, int user) | |||
445 | if (atomic_dec_and_test(&ps3fb.f_count)) { | 478 | if (atomic_dec_and_test(&ps3fb.f_count)) { |
446 | if (atomic_read(&ps3fb.ext_flip)) { | 479 | if (atomic_read(&ps3fb.ext_flip)) { |
447 | atomic_set(&ps3fb.ext_flip, 0); | 480 | atomic_set(&ps3fb.ext_flip, 0); |
448 | ps3fb_sync(0); /* single buffer */ | 481 | ps3fb_sync(info, 0); /* single buffer */ |
449 | } | 482 | } |
450 | } | 483 | } |
451 | return 0; | 484 | return 0; |
@@ -461,39 +494,37 @@ static int ps3fb_release(struct fb_info *info, int user) | |||
461 | 494 | ||
462 | static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 495 | static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
463 | { | 496 | { |
464 | u32 line_length; | 497 | u32 xdr_line_length, ddr_line_length; |
465 | int mode; | 498 | int mode; |
466 | int i; | ||
467 | 499 | ||
468 | DPRINTK("var->xres:%u info->var.xres:%u\n", var->xres, info->var.xres); | 500 | dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres, |
469 | DPRINTK("var->yres:%u info->var.yres:%u\n", var->yres, info->var.yres); | 501 | info->var.xres); |
502 | dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres, | ||
503 | info->var.yres); | ||
470 | 504 | ||
471 | /* FIXME For now we do exact matches only */ | 505 | /* FIXME For now we do exact matches only */ |
472 | mode = ps3fb_find_mode(var, &line_length); | 506 | mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length); |
473 | if (!mode) | 507 | if (!mode) |
474 | return -EINVAL; | 508 | return -EINVAL; |
475 | 509 | ||
476 | /* | 510 | /* Virtual screen */ |
477 | * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! | 511 | if (var->xres_virtual < var->xres) |
478 | * as FB_VMODE_SMOOTH_XPAN is only used internally | 512 | var->xres_virtual = var->xres; |
479 | */ | 513 | if (var->yres_virtual < var->yres) |
514 | var->yres_virtual = var->yres; | ||
480 | 515 | ||
481 | if (var->vmode & FB_VMODE_CONUPDATE) { | 516 | if (var->xres_virtual > xdr_line_length / BPP) { |
482 | var->vmode |= FB_VMODE_YWRAP; | 517 | dev_dbg(info->device, |
483 | var->xoffset = info->var.xoffset; | 518 | "Horizontal virtual screen size too large\n"); |
484 | var->yoffset = info->var.yoffset; | 519 | return -EINVAL; |
485 | } | 520 | } |
486 | 521 | ||
487 | /* Virtual screen and panning are not supported */ | 522 | if (var->xoffset + var->xres > var->xres_virtual || |
488 | if (var->xres_virtual > var->xres || var->yres_virtual > var->yres || | 523 | var->yoffset + var->yres > var->yres_virtual) { |
489 | var->xoffset || var->yoffset) { | 524 | dev_dbg(info->device, "panning out-of-range\n"); |
490 | DPRINTK("Virtual screen and panning are not supported\n"); | ||
491 | return -EINVAL; | 525 | return -EINVAL; |
492 | } | 526 | } |
493 | 527 | ||
494 | var->xres_virtual = var->xres; | ||
495 | var->yres_virtual = var->yres; | ||
496 | |||
497 | /* We support ARGB8888 only */ | 528 | /* We support ARGB8888 only */ |
498 | if (var->bits_per_pixel > 32 || var->grayscale || | 529 | if (var->bits_per_pixel > 32 || var->grayscale || |
499 | var->red.offset > 16 || var->green.offset > 8 || | 530 | var->red.offset > 16 || var->green.offset > 8 || |
@@ -502,7 +533,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
502 | var->blue.length > 8 || var->transp.length > 8 || | 533 | var->blue.length > 8 || var->transp.length > 8 || |
503 | var->red.msb_right || var->green.msb_right || | 534 | var->red.msb_right || var->green.msb_right || |
504 | var->blue.msb_right || var->transp.msb_right || var->nonstd) { | 535 | var->blue.msb_right || var->transp.msb_right || var->nonstd) { |
505 | DPRINTK("We support ARGB8888 only\n"); | 536 | dev_dbg(info->device, "We support ARGB8888 only\n"); |
506 | return -EINVAL; | 537 | return -EINVAL; |
507 | } | 538 | } |
508 | 539 | ||
@@ -522,14 +553,13 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
522 | 553 | ||
523 | /* Rotation is not supported */ | 554 | /* Rotation is not supported */ |
524 | if (var->rotate) { | 555 | if (var->rotate) { |
525 | DPRINTK("Rotation is not supported\n"); | 556 | dev_dbg(info->device, "Rotation is not supported\n"); |
526 | return -EINVAL; | 557 | return -EINVAL; |
527 | } | 558 | } |
528 | 559 | ||
529 | /* Memory limit */ | 560 | /* Memory limit */ |
530 | i = ps3fb_get_res_table(var->xres, var->yres); | 561 | if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) { |
531 | if (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP > ps3fb_videomemory.size) { | 562 | dev_dbg(info->device, "Not enough memory\n"); |
532 | DPRINTK("Not enough memory\n"); | ||
533 | return -ENOMEM; | 563 | return -ENOMEM; |
534 | } | 564 | } |
535 | 565 | ||
@@ -545,36 +575,69 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
545 | 575 | ||
546 | static int ps3fb_set_par(struct fb_info *info) | 576 | static int ps3fb_set_par(struct fb_info *info) |
547 | { | 577 | { |
548 | unsigned int mode; | 578 | struct ps3fb_par *par = info->par; |
579 | unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; | ||
549 | int i; | 580 | int i; |
550 | unsigned long offset; | 581 | unsigned long offset; |
551 | static int first = 1; | 582 | u64 dst; |
552 | 583 | ||
553 | DPRINTK("xres:%d xv:%d yres:%d yv:%d clock:%d\n", | 584 | dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", |
554 | info->var.xres, info->var.xres_virtual, | 585 | info->var.xres, info->var.xres_virtual, |
555 | info->var.yres, info->var.yres_virtual, info->var.pixclock); | 586 | info->var.yres, info->var.yres_virtual, info->var.pixclock); |
556 | i = ps3fb_get_res_table(info->var.xres, info->var.yres); | ||
557 | ps3fb.res_index = i; | ||
558 | 587 | ||
559 | mode = ps3fb_find_mode(&info->var, &info->fix.line_length); | 588 | mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length); |
560 | if (!mode) | 589 | if (!mode) |
561 | return -EINVAL; | 590 | return -EINVAL; |
562 | 591 | ||
563 | offset = FB_OFF(i) + VP_OFF(i); | 592 | i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); |
564 | info->fix.smem_len = ps3fb_videomemory.size - offset; | 593 | par->res_index = i; |
565 | info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; | 594 | |
566 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | 595 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); |
596 | info->fix.smem_len = ps3fb.xdr_size; | ||
597 | info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; | ||
598 | info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; | ||
599 | info->fix.line_length = xdr_line_length; | ||
600 | |||
601 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; | ||
567 | 602 | ||
568 | ps3fb.num_frames = ps3fb_videomemory.size/ | 603 | par->num_frames = ps3fb.xdr_size / |
569 | (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP); | 604 | max(ps3fb_res[i].yres * ddr_line_length, |
605 | info->var.yres_virtual * xdr_line_length); | ||
570 | 606 | ||
571 | /* Keep the special bits we cannot set using fb_var_screeninfo */ | 607 | /* Keep the special bits we cannot set using fb_var_screeninfo */ |
572 | ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode; | 608 | par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; |
609 | |||
610 | par->width = info->var.xres; | ||
611 | par->height = info->var.yres; | ||
612 | offset = VP_OFF(i); | ||
613 | par->fb_offset = GPU_ALIGN_UP(offset); | ||
614 | par->full_offset = par->fb_offset - offset; | ||
615 | par->pan_offset = info->var.yoffset * xdr_line_length + | ||
616 | info->var.xoffset * BPP; | ||
617 | |||
618 | if (par->new_mode_id != par->mode_id) { | ||
619 | if (ps3av_set_video_mode(par->new_mode_id)) { | ||
620 | par->new_mode_id = par->mode_id; | ||
621 | return -EINVAL; | ||
622 | } | ||
623 | par->mode_id = par->new_mode_id; | ||
624 | } | ||
573 | 625 | ||
574 | if (ps3av_set_video_mode(ps3fb_mode, first)) | 626 | /* Clear XDR frame buffer memory */ |
575 | return -EINVAL; | 627 | memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); |
628 | |||
629 | /* Clear DDR frame buffer memory */ | ||
630 | lines = ps3fb_res[i].yres * par->num_frames; | ||
631 | if (par->full_offset) | ||
632 | lines++; | ||
633 | maxlines = ps3fb.xdr_size / ddr_line_length; | ||
634 | for (dst = 0; lines; dst += maxlines * ddr_line_length) { | ||
635 | unsigned int l = min(lines, maxlines); | ||
636 | ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, | ||
637 | ddr_line_length, ddr_line_length); | ||
638 | lines -= l; | ||
639 | } | ||
576 | 640 | ||
577 | first = 0; | ||
578 | return 0; | 641 | return 0; |
579 | } | 642 | } |
580 | 643 | ||
@@ -601,6 +664,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red, | |||
601 | return 0; | 664 | return 0; |
602 | } | 665 | } |
603 | 666 | ||
667 | static int ps3fb_pan_display(struct fb_var_screeninfo *var, | ||
668 | struct fb_info *info) | ||
669 | { | ||
670 | struct ps3fb_par *par = info->par; | ||
671 | |||
672 | par->pan_offset = var->yoffset * info->fix.line_length + | ||
673 | var->xoffset * BPP; | ||
674 | return 0; | ||
675 | } | ||
676 | |||
604 | /* | 677 | /* |
605 | * As we have a virtual frame buffer, we need our own mmap function | 678 | * As we have a virtual frame buffer, we need our own mmap function |
606 | */ | 679 | */ |
@@ -608,24 +681,19 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red, | |||
608 | static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | 681 | static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) |
609 | { | 682 | { |
610 | unsigned long size, offset; | 683 | unsigned long size, offset; |
611 | int i; | ||
612 | |||
613 | i = ps3fb_get_res_table(info->var.xres, info->var.yres); | ||
614 | if (i == -1) | ||
615 | return -EINVAL; | ||
616 | 684 | ||
617 | size = vma->vm_end - vma->vm_start; | 685 | size = vma->vm_end - vma->vm_start; |
618 | offset = vma->vm_pgoff << PAGE_SHIFT; | 686 | offset = vma->vm_pgoff << PAGE_SHIFT; |
619 | if (offset + size > info->fix.smem_len) | 687 | if (offset + size > info->fix.smem_len) |
620 | return -EINVAL; | 688 | return -EINVAL; |
621 | 689 | ||
622 | offset += info->fix.smem_start + FB_OFF(i) + VP_OFF(i); | 690 | offset += info->fix.smem_start; |
623 | if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, | 691 | if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, |
624 | size, vma->vm_page_prot)) | 692 | size, vma->vm_page_prot)) |
625 | return -EAGAIN; | 693 | return -EAGAIN; |
626 | 694 | ||
627 | printk(KERN_DEBUG "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", offset, | 695 | dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", |
628 | vma->vm_start); | 696 | offset, vma->vm_start); |
629 | return 0; | 697 | return 0; |
630 | } | 698 | } |
631 | 699 | ||
@@ -637,7 +705,7 @@ static int ps3fb_blank(int blank, struct fb_info *info) | |||
637 | { | 705 | { |
638 | int retval; | 706 | int retval; |
639 | 707 | ||
640 | DPRINTK("%s: blank:%d\n", __func__, blank); | 708 | dev_dbg(info->device, "%s: blank:%d\n", __func__, blank); |
641 | switch (blank) { | 709 | switch (blank) { |
642 | case FB_BLANK_POWERDOWN: | 710 | case FB_BLANK_POWERDOWN: |
643 | case FB_BLANK_HSYNC_SUSPEND: | 711 | case FB_BLANK_HSYNC_SUSPEND: |
@@ -664,7 +732,7 @@ static int ps3fb_get_vblank(struct fb_vblank *vblank) | |||
664 | return 0; | 732 | return 0; |
665 | } | 733 | } |
666 | 734 | ||
667 | int ps3fb_wait_for_vsync(u32 crtc) | 735 | static int ps3fb_wait_for_vsync(u32 crtc) |
668 | { | 736 | { |
669 | int ret; | 737 | int ret; |
670 | u64 count; | 738 | u64 count; |
@@ -679,9 +747,7 @@ int ps3fb_wait_for_vsync(u32 crtc) | |||
679 | return 0; | 747 | return 0; |
680 | } | 748 | } |
681 | 749 | ||
682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); | 750 | static void ps3fb_flip_ctl(int on, void *data) |
683 | |||
684 | void ps3fb_flip_ctl(int on, void *data) | ||
685 | { | 751 | { |
686 | struct ps3fb_priv *priv = data; | 752 | struct ps3fb_priv *priv = data; |
687 | if (on) | 753 | if (on) |
@@ -699,14 +765,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
699 | unsigned long arg) | 765 | unsigned long arg) |
700 | { | 766 | { |
701 | void __user *argp = (void __user *)arg; | 767 | void __user *argp = (void __user *)arg; |
702 | u32 val, old_mode; | 768 | u32 val; |
703 | int retval = -EFAULT; | 769 | int retval = -EFAULT; |
704 | 770 | ||
705 | switch (cmd) { | 771 | switch (cmd) { |
706 | case FBIOGET_VBLANK: | 772 | case FBIOGET_VBLANK: |
707 | { | 773 | { |
708 | struct fb_vblank vblank; | 774 | struct fb_vblank vblank; |
709 | DPRINTK("FBIOGET_VBLANK:\n"); | 775 | dev_dbg(info->device, "FBIOGET_VBLANK:\n"); |
710 | retval = ps3fb_get_vblank(&vblank); | 776 | retval = ps3fb_get_vblank(&vblank); |
711 | if (retval) | 777 | if (retval) |
712 | break; | 778 | break; |
@@ -719,7 +785,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
719 | case FBIO_WAITFORVSYNC: | 785 | case FBIO_WAITFORVSYNC: |
720 | { | 786 | { |
721 | u32 crt; | 787 | u32 crt; |
722 | DPRINTK("FBIO_WAITFORVSYNC:\n"); | 788 | dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n"); |
723 | if (get_user(crt, (u32 __user *) arg)) | 789 | if (get_user(crt, (u32 __user *) arg)) |
724 | break; | 790 | break; |
725 | 791 | ||
@@ -729,6 +795,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
729 | 795 | ||
730 | case PS3FB_IOCTL_SETMODE: | 796 | case PS3FB_IOCTL_SETMODE: |
731 | { | 797 | { |
798 | struct ps3fb_par *par = info->par; | ||
732 | const struct fb_videomode *mode; | 799 | const struct fb_videomode *mode; |
733 | struct fb_var_screeninfo var; | 800 | struct fb_var_screeninfo var; |
734 | 801 | ||
@@ -736,15 +803,13 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
736 | break; | 803 | break; |
737 | 804 | ||
738 | if (!(val & PS3AV_MODE_MASK)) { | 805 | if (!(val & PS3AV_MODE_MASK)) { |
739 | u32 id = ps3av_get_auto_mode(0); | 806 | u32 id = ps3av_get_auto_mode(); |
740 | if (id > 0) | 807 | if (id > 0) |
741 | val = (val & ~PS3AV_MODE_MASK) | id; | 808 | val = (val & ~PS3AV_MODE_MASK) | id; |
742 | } | 809 | } |
743 | DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val); | 810 | dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); |
744 | retval = -EINVAL; | 811 | retval = -EINVAL; |
745 | old_mode = ps3fb_mode; | 812 | mode = ps3fb_default_mode(val); |
746 | ps3fb_mode = val; | ||
747 | mode = ps3fb_default_mode(); | ||
748 | if (mode) { | 813 | if (mode) { |
749 | var = info->var; | 814 | var = info->var; |
750 | fb_videomode_to_var(&var, mode); | 815 | fb_videomode_to_var(&var, mode); |
@@ -752,45 +817,44 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
752 | info->flags |= FBINFO_MISC_USEREVENT; | 817 | info->flags |= FBINFO_MISC_USEREVENT; |
753 | /* Force, in case only special bits changed */ | 818 | /* Force, in case only special bits changed */ |
754 | var.activate |= FB_ACTIVATE_FORCE; | 819 | var.activate |= FB_ACTIVATE_FORCE; |
820 | par->new_mode_id = val; | ||
755 | retval = fb_set_var(info, &var); | 821 | retval = fb_set_var(info, &var); |
756 | info->flags &= ~FBINFO_MISC_USEREVENT; | 822 | info->flags &= ~FBINFO_MISC_USEREVENT; |
757 | release_console_sem(); | 823 | release_console_sem(); |
758 | } | 824 | } |
759 | if (retval) | ||
760 | ps3fb_mode = old_mode; | ||
761 | break; | 825 | break; |
762 | } | 826 | } |
763 | 827 | ||
764 | case PS3FB_IOCTL_GETMODE: | 828 | case PS3FB_IOCTL_GETMODE: |
765 | val = ps3av_get_mode(); | 829 | val = ps3av_get_mode(); |
766 | DPRINTK("PS3FB_IOCTL_GETMODE:%x\n", val); | 830 | dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val); |
767 | if (!copy_to_user(argp, &val, sizeof(val))) | 831 | if (!copy_to_user(argp, &val, sizeof(val))) |
768 | retval = 0; | 832 | retval = 0; |
769 | break; | 833 | break; |
770 | 834 | ||
771 | case PS3FB_IOCTL_SCREENINFO: | 835 | case PS3FB_IOCTL_SCREENINFO: |
772 | { | 836 | { |
837 | struct ps3fb_par *par = info->par; | ||
773 | struct ps3fb_ioctl_res res; | 838 | struct ps3fb_ioctl_res res; |
774 | int i = ps3fb.res_index; | 839 | dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n"); |
775 | DPRINTK("PS3FB_IOCTL_SCREENINFO:\n"); | 840 | res.xres = info->fix.line_length / BPP; |
776 | res.xres = ps3fb_res[i].xres; | 841 | res.yres = info->var.yres_virtual; |
777 | res.yres = ps3fb_res[i].yres; | 842 | res.xoff = (res.xres - info->var.xres) / 2; |
778 | res.xoff = ps3fb_res[i].xoff; | 843 | res.yoff = (res.yres - info->var.yres) / 2; |
779 | res.yoff = ps3fb_res[i].yoff; | 844 | res.num_frames = par->num_frames; |
780 | res.num_frames = ps3fb.num_frames; | ||
781 | if (!copy_to_user(argp, &res, sizeof(res))) | 845 | if (!copy_to_user(argp, &res, sizeof(res))) |
782 | retval = 0; | 846 | retval = 0; |
783 | break; | 847 | break; |
784 | } | 848 | } |
785 | 849 | ||
786 | case PS3FB_IOCTL_ON: | 850 | case PS3FB_IOCTL_ON: |
787 | DPRINTK("PS3FB_IOCTL_ON:\n"); | 851 | dev_dbg(info->device, "PS3FB_IOCTL_ON:\n"); |
788 | atomic_inc(&ps3fb.ext_flip); | 852 | atomic_inc(&ps3fb.ext_flip); |
789 | retval = 0; | 853 | retval = 0; |
790 | break; | 854 | break; |
791 | 855 | ||
792 | case PS3FB_IOCTL_OFF: | 856 | case PS3FB_IOCTL_OFF: |
793 | DPRINTK("PS3FB_IOCTL_OFF:\n"); | 857 | dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n"); |
794 | atomic_dec_if_positive(&ps3fb.ext_flip); | 858 | atomic_dec_if_positive(&ps3fb.ext_flip); |
795 | retval = 0; | 859 | retval = 0; |
796 | break; | 860 | break; |
@@ -799,8 +863,8 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
799 | if (copy_from_user(&val, argp, sizeof(val))) | 863 | if (copy_from_user(&val, argp, sizeof(val))) |
800 | break; | 864 | break; |
801 | 865 | ||
802 | DPRINTK("PS3FB_IOCTL_FSEL:%d\n", val); | 866 | dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val); |
803 | retval = ps3fb_sync(val); | 867 | retval = ps3fb_sync(info, val); |
804 | break; | 868 | break; |
805 | 869 | ||
806 | default: | 870 | default: |
@@ -812,13 +876,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
812 | 876 | ||
813 | static int ps3fbd(void *arg) | 877 | static int ps3fbd(void *arg) |
814 | { | 878 | { |
879 | struct fb_info *info = arg; | ||
880 | |||
815 | set_freezable(); | 881 | set_freezable(); |
816 | while (!kthread_should_stop()) { | 882 | while (!kthread_should_stop()) { |
817 | try_to_freeze(); | 883 | try_to_freeze(); |
818 | set_current_state(TASK_INTERRUPTIBLE); | 884 | set_current_state(TASK_INTERRUPTIBLE); |
819 | if (ps3fb.is_kicked) { | 885 | if (ps3fb.is_kicked) { |
820 | ps3fb.is_kicked = 0; | 886 | ps3fb.is_kicked = 0; |
821 | ps3fb_sync(0); /* single buffer */ | 887 | ps3fb_sync(info, 0); /* single buffer */ |
822 | } | 888 | } |
823 | schedule(); | 889 | schedule(); |
824 | } | 890 | } |
@@ -827,14 +893,15 @@ static int ps3fbd(void *arg) | |||
827 | 893 | ||
828 | static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | 894 | static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) |
829 | { | 895 | { |
896 | struct device *dev = ptr; | ||
830 | u64 v1; | 897 | u64 v1; |
831 | int status; | 898 | int status; |
832 | struct display_head *head = &ps3fb.dinfo->display_head[1]; | 899 | struct display_head *head = &ps3fb.dinfo->display_head[1]; |
833 | 900 | ||
834 | status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); | 901 | status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); |
835 | if (status) { | 902 | if (status) { |
836 | printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n", | 903 | dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__, |
837 | __func__, status); | 904 | status); |
838 | return IRQ_NONE; | 905 | return IRQ_NONE; |
839 | } | 906 | } |
840 | 907 | ||
@@ -854,35 +921,35 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | |||
854 | 921 | ||
855 | 922 | ||
856 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, | 923 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, |
857 | struct ps3_system_bus_device *dev) | 924 | struct device *dev) |
858 | { | 925 | { |
859 | int error; | 926 | int error; |
860 | 927 | ||
861 | DPRINTK("version_driver:%x\n", dinfo->version_driver); | 928 | dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); |
862 | DPRINTK("irq outlet:%x\n", dinfo->irq.irq_outlet); | 929 | dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); |
863 | DPRINTK("version_gpu:%x memory_size:%x ch:%x core_freq:%d mem_freq:%d\n", | 930 | dev_dbg(dev, |
931 | "version_gpu: %x memory_size: %x ch: %x core_freq: %d " | ||
932 | "mem_freq:%d\n", | ||
864 | dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, | 933 | dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, |
865 | dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); | 934 | dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); |
866 | 935 | ||
867 | if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { | 936 | if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { |
868 | printk(KERN_ERR "%s: version_driver err:%x\n", __func__, | 937 | dev_err(dev, "%s: version_driver err:%x\n", __func__, |
869 | dinfo->version_driver); | 938 | dinfo->version_driver); |
870 | return -EINVAL; | 939 | return -EINVAL; |
871 | } | 940 | } |
872 | 941 | ||
873 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | 942 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, |
874 | &ps3fb.irq_no); | 943 | &ps3fb.irq_no); |
875 | if (error) { | 944 | if (error) { |
876 | printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__, | 945 | dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); |
877 | error); | ||
878 | return error; | 946 | return error; |
879 | } | 947 | } |
880 | 948 | ||
881 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, | 949 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, |
882 | DEVICE_NAME, dev); | 950 | DEVICE_NAME, dev); |
883 | if (error) { | 951 | if (error) { |
884 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, | 952 | dev_err(dev, "%s: request_irq failed %d\n", __func__, error); |
885 | error); | ||
886 | ps3_irq_plug_destroy(ps3fb.irq_no); | 953 | ps3_irq_plug_destroy(ps3fb.irq_no); |
887 | return error; | 954 | return error; |
888 | } | 955 | } |
@@ -892,29 +959,31 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, | |||
892 | return 0; | 959 | return 0; |
893 | } | 960 | } |
894 | 961 | ||
895 | static int ps3fb_xdr_settings(u64 xdr_lpar) | 962 | static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) |
896 | { | 963 | { |
897 | int status; | 964 | int status; |
898 | 965 | ||
899 | status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, | 966 | status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, |
900 | xdr_lpar, ps3fb_videomemory.size, 0); | 967 | xdr_lpar, ps3fb_videomemory.size, 0); |
901 | if (status) { | 968 | if (status) { |
902 | printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n", | 969 | dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", |
903 | __func__, status); | 970 | __func__, status); |
904 | return -ENXIO; | 971 | return -ENXIO; |
905 | } | 972 | } |
906 | DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", | 973 | dev_dbg(dev, |
974 | "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", | ||
907 | ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, | 975 | ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, |
908 | virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); | 976 | virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); |
909 | 977 | ||
910 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 978 | status = lv1_gpu_context_attribute(ps3fb.context_handle, |
911 | L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, | 979 | L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, |
912 | xdr_lpar, ps3fb_videomemory.size, | 980 | xdr_lpar + ps3fb.xdr_size, |
913 | GPU_IOIF, 0); | 981 | GPU_CMD_BUF_SIZE, |
982 | GPU_IOIF + ps3fb.xdr_size, 0); | ||
914 | if (status) { | 983 | if (status) { |
915 | printk(KERN_ERR | 984 | dev_err(dev, |
916 | "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", | 985 | "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", |
917 | __func__, status); | 986 | __func__, status); |
918 | return -ENXIO; | 987 | return -ENXIO; |
919 | } | 988 | } |
920 | return 0; | 989 | return 0; |
@@ -928,6 +997,7 @@ static struct fb_ops ps3fb_ops = { | |||
928 | .fb_check_var = ps3fb_check_var, | 997 | .fb_check_var = ps3fb_check_var, |
929 | .fb_set_par = ps3fb_set_par, | 998 | .fb_set_par = ps3fb_set_par, |
930 | .fb_setcolreg = ps3fb_setcolreg, | 999 | .fb_setcolreg = ps3fb_setcolreg, |
1000 | .fb_pan_display = ps3fb_pan_display, | ||
931 | .fb_fillrect = sys_fillrect, | 1001 | .fb_fillrect = sys_fillrect, |
932 | .fb_copyarea = sys_copyarea, | 1002 | .fb_copyarea = sys_copyarea, |
933 | .fb_imageblit = sys_imageblit, | 1003 | .fb_imageblit = sys_imageblit, |
@@ -944,7 +1014,7 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { | |||
944 | .accel = FB_ACCEL_NONE, | 1014 | .accel = FB_ACCEL_NONE, |
945 | }; | 1015 | }; |
946 | 1016 | ||
947 | static int ps3fb_set_sync(void) | 1017 | static int ps3fb_set_sync(struct device *dev) |
948 | { | 1018 | { |
949 | int status; | 1019 | int status; |
950 | 1020 | ||
@@ -953,8 +1023,10 @@ static int ps3fb_set_sync(void) | |||
953 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | 1023 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, |
954 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | 1024 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); |
955 | if (status) { | 1025 | if (status) { |
956 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " | 1026 | dev_err(dev, |
957 | "failed: %d\n", __func__, status); | 1027 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " |
1028 | "%d\n", | ||
1029 | __func__, status); | ||
958 | return -1; | 1030 | return -1; |
959 | } | 1031 | } |
960 | #endif | 1032 | #endif |
@@ -964,8 +1036,10 @@ static int ps3fb_set_sync(void) | |||
964 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | 1036 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); |
965 | 1037 | ||
966 | if (status) { | 1038 | if (status) { |
967 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " | 1039 | dev_err(dev, |
968 | "failed: %d\n", __func__, status); | 1040 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " |
1041 | "%d\n", | ||
1042 | __func__, status); | ||
969 | return -1; | 1043 | return -1; |
970 | } | 1044 | } |
971 | #endif | 1045 | #endif |
@@ -975,6 +1049,7 @@ static int ps3fb_set_sync(void) | |||
975 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | 1049 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) |
976 | { | 1050 | { |
977 | struct fb_info *info; | 1051 | struct fb_info *info; |
1052 | struct ps3fb_par *par; | ||
978 | int retval = -ENOMEM; | 1053 | int retval = -ENOMEM; |
979 | u32 xres, yres; | 1054 | u32 xres, yres; |
980 | u64 ddr_lpar = 0; | 1055 | u64 ddr_lpar = 0; |
@@ -983,98 +1058,106 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
983 | u64 lpar_reports = 0; | 1058 | u64 lpar_reports = 0; |
984 | u64 lpar_reports_size = 0; | 1059 | u64 lpar_reports_size = 0; |
985 | u64 xdr_lpar; | 1060 | u64 xdr_lpar; |
986 | int status; | 1061 | int status, res_index; |
987 | unsigned long offset; | ||
988 | struct task_struct *task; | 1062 | struct task_struct *task; |
989 | 1063 | ||
990 | status = ps3_open_hv_device(dev); | 1064 | status = ps3_open_hv_device(dev); |
991 | if (status) { | 1065 | if (status) { |
992 | printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__); | 1066 | dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", |
1067 | __func__); | ||
993 | goto err; | 1068 | goto err; |
994 | } | 1069 | } |
995 | 1070 | ||
996 | if (!ps3fb_mode) | 1071 | if (!ps3fb_mode) |
997 | ps3fb_mode = ps3av_get_mode(); | 1072 | ps3fb_mode = ps3av_get_mode(); |
998 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | 1073 | dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode); |
999 | 1074 | ||
1000 | if (ps3fb_mode > 0 && | 1075 | if (ps3fb_mode > 0 && |
1001 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { | 1076 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { |
1002 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | 1077 | res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); |
1003 | DPRINTK("res_index:%d\n", ps3fb.res_index); | 1078 | dev_dbg(&dev->core, "res_index:%d\n", res_index); |
1004 | } else | 1079 | } else |
1005 | ps3fb.res_index = GPU_RES_INDEX; | 1080 | res_index = GPU_RES_INDEX; |
1006 | 1081 | ||
1007 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | 1082 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ |
1008 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1083 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ |
1009 | init_waitqueue_head(&ps3fb.wait_vsync); | 1084 | init_waitqueue_head(&ps3fb.wait_vsync); |
1010 | ps3fb.num_frames = 1; | ||
1011 | 1085 | ||
1012 | ps3fb_set_sync(); | 1086 | ps3fb_set_sync(&dev->core); |
1013 | 1087 | ||
1014 | /* get gpu context handle */ | 1088 | /* get gpu context handle */ |
1015 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, | 1089 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, |
1016 | &ps3fb.memory_handle, &ddr_lpar); | 1090 | &ps3fb.memory_handle, &ddr_lpar); |
1017 | if (status) { | 1091 | if (status) { |
1018 | printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n", | 1092 | dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", |
1019 | __func__, status); | 1093 | __func__, status); |
1020 | goto err; | 1094 | goto err; |
1021 | } | 1095 | } |
1022 | DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar); | 1096 | dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar); |
1023 | 1097 | ||
1024 | status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0, | 1098 | status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0, |
1025 | &ps3fb.context_handle, | 1099 | &ps3fb.context_handle, |
1026 | &lpar_dma_control, &lpar_driver_info, | 1100 | &lpar_dma_control, &lpar_driver_info, |
1027 | &lpar_reports, &lpar_reports_size); | 1101 | &lpar_reports, &lpar_reports_size); |
1028 | if (status) { | 1102 | if (status) { |
1029 | printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n", | 1103 | dev_err(&dev->core, |
1030 | __func__, status); | 1104 | "%s: lv1_gpu_context_attribute failed: %d\n", __func__, |
1105 | status); | ||
1031 | goto err_gpu_memory_free; | 1106 | goto err_gpu_memory_free; |
1032 | } | 1107 | } |
1033 | 1108 | ||
1034 | /* vsync interrupt */ | 1109 | /* vsync interrupt */ |
1035 | ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); | 1110 | ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); |
1036 | if (!ps3fb.dinfo) { | 1111 | if (!ps3fb.dinfo) { |
1037 | printk(KERN_ERR "%s: ioremap failed\n", __func__); | 1112 | dev_err(&dev->core, "%s: ioremap failed\n", __func__); |
1038 | goto err_gpu_context_free; | 1113 | goto err_gpu_context_free; |
1039 | } | 1114 | } |
1040 | 1115 | ||
1041 | retval = ps3fb_vsync_settings(ps3fb.dinfo, dev); | 1116 | retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); |
1042 | if (retval) | 1117 | if (retval) |
1043 | goto err_iounmap_dinfo; | 1118 | goto err_iounmap_dinfo; |
1044 | 1119 | ||
1045 | /* xdr frame buffer */ | 1120 | /* XDR frame buffer */ |
1046 | ps3fb.xdr_ea = ps3fb_videomemory.address; | 1121 | ps3fb.xdr_ea = ps3fb_videomemory.address; |
1047 | xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); | 1122 | xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); |
1048 | retval = ps3fb_xdr_settings(xdr_lpar); | 1123 | |
1124 | /* Clear memory to prevent kernel info leakage into userspace */ | ||
1125 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | ||
1126 | |||
1127 | /* The GPU command buffer is at the end of video memory */ | ||
1128 | ps3fb.xdr_size = ps3fb_videomemory.size - GPU_CMD_BUF_SIZE; | ||
1129 | |||
1130 | retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); | ||
1049 | if (retval) | 1131 | if (retval) |
1050 | goto err_free_irq; | 1132 | goto err_free_irq; |
1051 | 1133 | ||
1052 | /* | 1134 | info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); |
1053 | * ps3fb must clear memory to prevent kernel info | ||
1054 | * leakage into userspace | ||
1055 | */ | ||
1056 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | ||
1057 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); | ||
1058 | if (!info) | 1135 | if (!info) |
1059 | goto err_free_irq; | 1136 | goto err_free_irq; |
1060 | 1137 | ||
1061 | offset = FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index); | 1138 | par = info->par; |
1062 | info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; | 1139 | par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ |
1140 | par->new_mode_id = ps3fb_mode; | ||
1141 | par->res_index = res_index; | ||
1142 | par->num_frames = 1; | ||
1143 | |||
1144 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; | ||
1063 | info->fbops = &ps3fb_ops; | 1145 | info->fbops = &ps3fb_ops; |
1064 | 1146 | ||
1065 | info->fix = ps3fb_fix; | 1147 | info->fix = ps3fb_fix; |
1066 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); | 1148 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); |
1067 | info->fix.smem_len = ps3fb_videomemory.size - offset; | 1149 | info->fix.smem_len = ps3fb.xdr_size; |
1068 | info->pseudo_palette = info->par; | 1150 | info->pseudo_palette = par->pseudo_palette; |
1069 | info->par = NULL; | 1151 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | |
1070 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; | 1152 | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; |
1071 | 1153 | ||
1072 | retval = fb_alloc_cmap(&info->cmap, 256, 0); | 1154 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
1073 | if (retval < 0) | 1155 | if (retval < 0) |
1074 | goto err_framebuffer_release; | 1156 | goto err_framebuffer_release; |
1075 | 1157 | ||
1076 | if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, | 1158 | if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, |
1077 | ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) { | 1159 | ARRAY_SIZE(ps3fb_modedb), |
1160 | ps3fb_default_mode(par->new_mode_id), 32)) { | ||
1078 | retval = -EINVAL; | 1161 | retval = -EINVAL; |
1079 | goto err_fb_dealloc; | 1162 | goto err_fb_dealloc; |
1080 | } | 1163 | } |
@@ -1088,9 +1171,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1088 | 1171 | ||
1089 | dev->core.driver_data = info; | 1172 | dev->core.driver_data = info; |
1090 | 1173 | ||
1091 | printk(KERN_INFO | 1174 | dev_info(info->device, "%s %s, using %lu KiB of video memory\n", |
1092 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", | 1175 | dev_driver_string(info->dev), info->dev->bus_id, |
1093 | info->node, ps3fb_videomemory.size >> 10); | 1176 | ps3fb.xdr_size >> 10); |
1094 | 1177 | ||
1095 | task = kthread_run(ps3fbd, info, DEVICE_NAME); | 1178 | task = kthread_run(ps3fbd, info, DEVICE_NAME); |
1096 | if (IS_ERR(task)) { | 1179 | if (IS_ERR(task)) { |
@@ -1127,7 +1210,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) | |||
1127 | int status; | 1210 | int status; |
1128 | struct fb_info *info = dev->core.driver_data; | 1211 | struct fb_info *info = dev->core.driver_data; |
1129 | 1212 | ||
1130 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); | 1213 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); |
1131 | 1214 | ||
1132 | ps3fb_flip_ctl(0, &ps3fb); /* flip off */ | 1215 | ps3fb_flip_ctl(0, &ps3fb); /* flip off */ |
1133 | ps3fb.dinfo->irq.mask = 0; | 1216 | ps3fb.dinfo->irq.mask = 0; |
@@ -1152,14 +1235,16 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) | |||
1152 | 1235 | ||
1153 | status = lv1_gpu_context_free(ps3fb.context_handle); | 1236 | status = lv1_gpu_context_free(ps3fb.context_handle); |
1154 | if (status) | 1237 | if (status) |
1155 | DPRINTK("lv1_gpu_context_free failed: %d\n", status); | 1238 | dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", |
1239 | status); | ||
1156 | 1240 | ||
1157 | status = lv1_gpu_memory_free(ps3fb.memory_handle); | 1241 | status = lv1_gpu_memory_free(ps3fb.memory_handle); |
1158 | if (status) | 1242 | if (status) |
1159 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); | 1243 | dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", |
1244 | status); | ||
1160 | 1245 | ||
1161 | ps3_close_hv_device(dev); | 1246 | ps3_close_hv_device(dev); |
1162 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); | 1247 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); |
1163 | 1248 | ||
1164 | return 0; | 1249 | return 0; |
1165 | } | 1250 | } |
@@ -1212,9 +1297,9 @@ static int __init ps3fb_init(void) | |||
1212 | 1297 | ||
1213 | static void __exit ps3fb_exit(void) | 1298 | static void __exit ps3fb_exit(void) |
1214 | { | 1299 | { |
1215 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); | 1300 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
1216 | ps3_system_bus_driver_unregister(&ps3fb_driver); | 1301 | ps3_system_bus_driver_unregister(&ps3fb_driver); |
1217 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); | 1302 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
1218 | } | 1303 | } |
1219 | 1304 | ||
1220 | module_init(ps3fb_init); | 1305 | module_init(ps3fb_init); |
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 06805c9b237b..6a3d0b574897 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c | |||
@@ -72,7 +72,7 @@ | |||
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | #ifdef CONFIG_SH_STORE_QUEUES | 74 | #ifdef CONFIG_SH_STORE_QUEUES |
75 | #include <asm/uaccess.h> | 75 | #include <linux/uaccess.h> |
76 | #include <asm/cpu/sq.h> | 76 | #include <asm/cpu/sq.h> |
77 | #endif | 77 | #endif |
78 | 78 | ||
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index f9b12ab59642..10f912df2dad 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <asm/hardware.h> | 43 | #include <asm/hardware.h> |
44 | #include <asm/io.h> | 44 | #include <asm/io.h> |
45 | #include <asm/irq.h> | 45 | #include <asm/irq.h> |
46 | #include <asm/uaccess.h> | ||
47 | #include <asm/div64.h> | 46 | #include <asm/div64.h> |
48 | #include <asm/arch/pxa-regs.h> | 47 | #include <asm/arch/pxa-regs.h> |
49 | #include <asm/arch/bitfield.h> | 48 | #include <asm/arch/bitfield.h> |
@@ -108,20 +107,38 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, | |||
108 | u_int trans, struct fb_info *info) | 107 | u_int trans, struct fb_info *info) |
109 | { | 108 | { |
110 | struct pxafb_info *fbi = (struct pxafb_info *)info; | 109 | struct pxafb_info *fbi = (struct pxafb_info *)info; |
111 | u_int val, ret = 1; | 110 | u_int val; |
112 | 111 | ||
113 | if (regno < fbi->palette_size) { | 112 | if (regno >= fbi->palette_size) |
114 | if (fbi->fb.var.grayscale) { | 113 | return 1; |
115 | val = ((blue >> 8) & 0x00ff); | 114 | |
116 | } else { | 115 | if (fbi->fb.var.grayscale) { |
117 | val = ((red >> 0) & 0xf800); | 116 | fbi->palette_cpu[regno] = ((blue >> 8) & 0x00ff); |
118 | val |= ((green >> 5) & 0x07e0); | 117 | return 0; |
119 | val |= ((blue >> 11) & 0x001f); | 118 | } |
120 | } | 119 | |
120 | switch (fbi->lccr4 & LCCR4_PAL_FOR_MASK) { | ||
121 | case LCCR4_PAL_FOR_0: | ||
122 | val = ((red >> 0) & 0xf800); | ||
123 | val |= ((green >> 5) & 0x07e0); | ||
124 | val |= ((blue >> 11) & 0x001f); | ||
121 | fbi->palette_cpu[regno] = val; | 125 | fbi->palette_cpu[regno] = val; |
122 | ret = 0; | 126 | break; |
127 | case LCCR4_PAL_FOR_1: | ||
128 | val = ((red << 8) & 0x00f80000); | ||
129 | val |= ((green >> 0) & 0x0000fc00); | ||
130 | val |= ((blue >> 8) & 0x000000f8); | ||
131 | ((u32*)(fbi->palette_cpu))[regno] = val; | ||
132 | break; | ||
133 | case LCCR4_PAL_FOR_2: | ||
134 | val = ((red << 8) & 0x00fc0000); | ||
135 | val |= ((green >> 0) & 0x0000fc00); | ||
136 | val |= ((blue >> 8) & 0x000000fc); | ||
137 | ((u32*)(fbi->palette_cpu))[regno] = val; | ||
138 | break; | ||
123 | } | 139 | } |
124 | return ret; | 140 | |
141 | return 0; | ||
125 | } | 142 | } |
126 | 143 | ||
127 | static int | 144 | static int |
@@ -363,7 +380,10 @@ static int pxafb_set_par(struct fb_info *info) | |||
363 | else | 380 | else |
364 | fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; | 381 | fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; |
365 | 382 | ||
366 | palette_mem_size = fbi->palette_size * sizeof(u16); | 383 | if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) |
384 | palette_mem_size = fbi->palette_size * sizeof(u16); | ||
385 | else | ||
386 | palette_mem_size = fbi->palette_size * sizeof(u32); | ||
367 | 387 | ||
368 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); | 388 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); |
369 | 389 | ||
@@ -680,7 +700,13 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * | |||
680 | 700 | ||
681 | fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; | 701 | fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; |
682 | fbi->dmadesc_palette_cpu->fidr = 0; | 702 | fbi->dmadesc_palette_cpu->fidr = 0; |
683 | fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; | 703 | if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) |
704 | fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * | ||
705 | sizeof(u16); | ||
706 | else | ||
707 | fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * | ||
708 | sizeof(u32); | ||
709 | fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL; | ||
684 | 710 | ||
685 | if (var->bits_per_pixel == 16) { | 711 | if (var->bits_per_pixel == 16) { |
686 | /* palette shouldn't be loaded in true-color mode */ | 712 | /* palette shouldn't be loaded in true-color mode */ |
@@ -719,6 +745,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * | |||
719 | fbi->reg_lccr1 = new_regs.lccr1; | 745 | fbi->reg_lccr1 = new_regs.lccr1; |
720 | fbi->reg_lccr2 = new_regs.lccr2; | 746 | fbi->reg_lccr2 = new_regs.lccr2; |
721 | fbi->reg_lccr3 = new_regs.lccr3; | 747 | fbi->reg_lccr3 = new_regs.lccr3; |
748 | fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK); | ||
749 | fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK); | ||
722 | set_hsync_time(fbi, pcd); | 750 | set_hsync_time(fbi, pcd); |
723 | local_irq_restore(flags); | 751 | local_irq_restore(flags); |
724 | 752 | ||
@@ -825,6 +853,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) | |||
825 | pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1); | 853 | pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1); |
826 | pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2); | 854 | pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2); |
827 | pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3); | 855 | pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3); |
856 | pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4); | ||
828 | } | 857 | } |
829 | 858 | ||
830 | static void pxafb_disable_controller(struct pxafb_info *fbi) | 859 | static void pxafb_disable_controller(struct pxafb_info *fbi) |
@@ -1094,10 +1123,13 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) | |||
1094 | * dma_writecombine_mmap) | 1123 | * dma_writecombine_mmap) |
1095 | */ | 1124 | */ |
1096 | fbi->fb.fix.smem_start = fbi->screen_dma; | 1125 | fbi->fb.fix.smem_start = fbi->screen_dma; |
1097 | |||
1098 | fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; | 1126 | fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; |
1099 | 1127 | ||
1100 | palette_mem_size = fbi->palette_size * sizeof(u16); | 1128 | if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) |
1129 | palette_mem_size = fbi->palette_size * sizeof(u16); | ||
1130 | else | ||
1131 | palette_mem_size = fbi->palette_size * sizeof(u32); | ||
1132 | |||
1101 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); | 1133 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); |
1102 | 1134 | ||
1103 | fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); | 1135 | fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); |
@@ -1160,6 +1192,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) | |||
1160 | 1192 | ||
1161 | fbi->lccr0 = inf->lccr0; | 1193 | fbi->lccr0 = inf->lccr0; |
1162 | fbi->lccr3 = inf->lccr3; | 1194 | fbi->lccr3 = inf->lccr3; |
1195 | fbi->lccr4 = inf->lccr4; | ||
1163 | fbi->state = C_STARTUP; | 1196 | fbi->state = C_STARTUP; |
1164 | fbi->task_state = (u_char)-1; | 1197 | fbi->task_state = (u_char)-1; |
1165 | 1198 | ||
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index f8605b807b0a..d920b8a14c35 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h | |||
@@ -71,6 +71,7 @@ struct pxafb_info { | |||
71 | 71 | ||
72 | u_int lccr0; | 72 | u_int lccr0; |
73 | u_int lccr3; | 73 | u_int lccr3; |
74 | u_int lccr4; | ||
74 | u_int cmap_inverse:1, | 75 | u_int cmap_inverse:1, |
75 | cmap_static:1, | 76 | cmap_static:1, |
76 | unused:30; | 77 | unused:30; |
@@ -79,6 +80,7 @@ struct pxafb_info { | |||
79 | u_int reg_lccr1; | 80 | u_int reg_lccr1; |
80 | u_int reg_lccr2; | 81 | u_int reg_lccr2; |
81 | u_int reg_lccr3; | 82 | u_int reg_lccr3; |
83 | u_int reg_lccr4; | ||
82 | 84 | ||
83 | unsigned long hsync_time; | 85 | unsigned long hsync_time; |
84 | 86 | ||
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 8a4c6470d799..ae08d4587091 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -20,7 +20,7 @@ | |||
20 | * | 20 | * |
21 | * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> | 21 | * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> |
22 | * - Added the possibility to set on or off the | 22 | * - Added the possibility to set on or off the |
23 | * debugging mesaages | 23 | * debugging messages |
24 | * - Replaced 0 and 1 by on or off when reading the | 24 | * - Replaced 0 and 1 by on or off when reading the |
25 | * /sys files | 25 | * /sys files |
26 | * | 26 | * |
@@ -31,8 +31,8 @@ | |||
31 | * - add pixel clock divisor control | 31 | * - add pixel clock divisor control |
32 | * | 32 | * |
33 | * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org> | 33 | * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org> |
34 | * - Removed the use of currcon as it no more exist | 34 | * - Removed the use of currcon as it no more exists |
35 | * - Added LCD power sysfs interface | 35 | * - Added LCD power sysfs interface |
36 | * | 36 | * |
37 | * 2004-11-03: Ben Dooks <ben-linux@fluff.org> | 37 | * 2004-11-03: Ben Dooks <ben-linux@fluff.org> |
38 | * - minor cleanups | 38 | * - minor cleanups |
@@ -49,12 +49,12 @@ | |||
49 | * - Suppress command line options | 49 | * - Suppress command line options |
50 | * | 50 | * |
51 | * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org> | 51 | * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org> |
52 | * - code cleanup | 52 | * - code cleanup |
53 | * | 53 | * |
54 | * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> | 54 | * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> |
55 | * - Renamed from h1940fb.c to s3c2410fb.c | 55 | * - Renamed from h1940fb.c to s3c2410fb.c |
56 | * - Add support for different devices | 56 | * - Add support for different devices |
57 | * - Backlight support | 57 | * - Backlight support |
58 | * | 58 | * |
59 | * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at> | 59 | * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at> |
60 | * - added clock (de-)allocation code | 60 | * - added clock (de-)allocation code |
@@ -82,13 +82,10 @@ | |||
82 | #include <linux/init.h> | 82 | #include <linux/init.h> |
83 | #include <linux/dma-mapping.h> | 83 | #include <linux/dma-mapping.h> |
84 | #include <linux/interrupt.h> | 84 | #include <linux/interrupt.h> |
85 | #include <linux/workqueue.h> | ||
86 | #include <linux/wait.h> | ||
87 | #include <linux/platform_device.h> | 85 | #include <linux/platform_device.h> |
88 | #include <linux/clk.h> | 86 | #include <linux/clk.h> |
89 | 87 | ||
90 | #include <asm/io.h> | 88 | #include <asm/io.h> |
91 | #include <asm/uaccess.h> | ||
92 | #include <asm/div64.h> | 89 | #include <asm/div64.h> |
93 | 90 | ||
94 | #include <asm/mach/map.h> | 91 | #include <asm/mach/map.h> |
@@ -102,14 +99,11 @@ | |||
102 | 99 | ||
103 | #include "s3c2410fb.h" | 100 | #include "s3c2410fb.h" |
104 | 101 | ||
105 | |||
106 | static struct s3c2410fb_mach_info *mach_info; | ||
107 | |||
108 | /* Debugging stuff */ | 102 | /* Debugging stuff */ |
109 | #ifdef CONFIG_FB_S3C2410_DEBUG | 103 | #ifdef CONFIG_FB_S3C2410_DEBUG |
110 | static int debug = 1; | 104 | static int debug = 1; |
111 | #else | 105 | #else |
112 | static int debug = 0; | 106 | static int debug = 0; |
113 | #endif | 107 | #endif |
114 | 108 | ||
115 | #define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } | 109 | #define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } |
@@ -119,48 +113,48 @@ static int debug = 0; | |||
119 | /* s3c2410fb_set_lcdaddr | 113 | /* s3c2410fb_set_lcdaddr |
120 | * | 114 | * |
121 | * initialise lcd controller address pointers | 115 | * initialise lcd controller address pointers |
122 | */ | 116 | */ |
123 | 117 | static void s3c2410fb_set_lcdaddr(struct fb_info *info) | |
124 | static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi) | ||
125 | { | 118 | { |
126 | struct fb_var_screeninfo *var = &fbi->fb->var; | ||
127 | unsigned long saddr1, saddr2, saddr3; | 119 | unsigned long saddr1, saddr2, saddr3; |
120 | struct s3c2410fb_info *fbi = info->par; | ||
121 | void __iomem *regs = fbi->io; | ||
128 | 122 | ||
129 | saddr1 = fbi->fb->fix.smem_start >> 1; | 123 | saddr1 = info->fix.smem_start >> 1; |
130 | saddr2 = fbi->fb->fix.smem_start; | 124 | saddr2 = info->fix.smem_start; |
131 | saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; | 125 | saddr2 += info->fix.line_length * info->var.yres; |
132 | saddr2>>= 1; | 126 | saddr2 >>= 1; |
133 | 127 | ||
134 | saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff); | 128 | saddr3 = S3C2410_OFFSIZE(0) | |
129 | S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff); | ||
135 | 130 | ||
136 | dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); | 131 | dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); |
137 | dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); | 132 | dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); |
138 | dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); | 133 | dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); |
139 | 134 | ||
140 | writel(saddr1, S3C2410_LCDSADDR1); | 135 | writel(saddr1, regs + S3C2410_LCDSADDR1); |
141 | writel(saddr2, S3C2410_LCDSADDR2); | 136 | writel(saddr2, regs + S3C2410_LCDSADDR2); |
142 | writel(saddr3, S3C2410_LCDSADDR3); | 137 | writel(saddr3, regs + S3C2410_LCDSADDR3); |
143 | } | 138 | } |
144 | 139 | ||
145 | /* s3c2410fb_calc_pixclk() | 140 | /* s3c2410fb_calc_pixclk() |
146 | * | 141 | * |
147 | * calculate divisor for clk->pixclk | 142 | * calculate divisor for clk->pixclk |
148 | */ | 143 | */ |
149 | |||
150 | static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, | 144 | static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, |
151 | unsigned long pixclk) | 145 | unsigned long pixclk) |
152 | { | 146 | { |
153 | unsigned long clk = clk_get_rate(fbi->clk); | 147 | unsigned long clk = clk_get_rate(fbi->clk); |
154 | unsigned long long div; | 148 | unsigned long long div; |
155 | 149 | ||
156 | /* pixclk is in picoseoncds, our clock is in Hz | 150 | /* pixclk is in picoseconds, our clock is in Hz |
157 | * | 151 | * |
158 | * Hz -> picoseconds is / 10^-12 | 152 | * Hz -> picoseconds is / 10^-12 |
159 | */ | 153 | */ |
160 | 154 | ||
161 | div = (unsigned long long)clk * pixclk; | 155 | div = (unsigned long long)clk * pixclk; |
162 | do_div(div,1000000UL); | 156 | div >>= 12; /* div / 2^12 */ |
163 | do_div(div,1000000UL); | 157 | do_div(div, 625 * 625UL * 625); /* div / 5^12 */ |
164 | 158 | ||
165 | dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div); | 159 | dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div); |
166 | return div; | 160 | return div; |
@@ -176,246 +170,278 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var, | |||
176 | struct fb_info *info) | 170 | struct fb_info *info) |
177 | { | 171 | { |
178 | struct s3c2410fb_info *fbi = info->par; | 172 | struct s3c2410fb_info *fbi = info->par; |
173 | struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; | ||
174 | struct s3c2410fb_display *display = NULL; | ||
175 | struct s3c2410fb_display *default_display = mach_info->displays + | ||
176 | mach_info->default_display; | ||
177 | int type = default_display->type; | ||
178 | unsigned i; | ||
179 | 179 | ||
180 | dprintk("check_var(var=%p, info=%p)\n", var, info); | 180 | dprintk("check_var(var=%p, info=%p)\n", var, info); |
181 | 181 | ||
182 | /* validate x/y resolution */ | 182 | /* validate x/y resolution */ |
183 | /* choose default mode if possible */ | ||
184 | if (var->yres == default_display->yres && | ||
185 | var->xres == default_display->xres && | ||
186 | var->bits_per_pixel == default_display->bpp) | ||
187 | display = default_display; | ||
188 | else | ||
189 | for (i = 0; i < mach_info->num_displays; i++) | ||
190 | if (type == mach_info->displays[i].type && | ||
191 | var->yres == mach_info->displays[i].yres && | ||
192 | var->xres == mach_info->displays[i].xres && | ||
193 | var->bits_per_pixel == mach_info->displays[i].bpp) { | ||
194 | display = mach_info->displays + i; | ||
195 | break; | ||
196 | } | ||
183 | 197 | ||
184 | if (var->yres > fbi->mach_info->yres.max) | 198 | if (!display) { |
185 | var->yres = fbi->mach_info->yres.max; | 199 | dprintk("wrong resolution or depth %dx%d at %d bpp\n", |
186 | else if (var->yres < fbi->mach_info->yres.min) | 200 | var->xres, var->yres, var->bits_per_pixel); |
187 | var->yres = fbi->mach_info->yres.min; | 201 | return -EINVAL; |
188 | 202 | } | |
189 | if (var->xres > fbi->mach_info->xres.max) | ||
190 | var->yres = fbi->mach_info->xres.max; | ||
191 | else if (var->xres < fbi->mach_info->xres.min) | ||
192 | var->xres = fbi->mach_info->xres.min; | ||
193 | |||
194 | /* validate bpp */ | ||
195 | |||
196 | if (var->bits_per_pixel > fbi->mach_info->bpp.max) | ||
197 | var->bits_per_pixel = fbi->mach_info->bpp.max; | ||
198 | else if (var->bits_per_pixel < fbi->mach_info->bpp.min) | ||
199 | var->bits_per_pixel = fbi->mach_info->bpp.min; | ||
200 | 203 | ||
204 | /* it is always the size as the display */ | ||
205 | var->xres_virtual = display->xres; | ||
206 | var->yres_virtual = display->yres; | ||
207 | var->height = display->height; | ||
208 | var->width = display->width; | ||
209 | |||
210 | /* copy lcd settings */ | ||
211 | var->pixclock = display->pixclock; | ||
212 | var->left_margin = display->left_margin; | ||
213 | var->right_margin = display->right_margin; | ||
214 | var->upper_margin = display->upper_margin; | ||
215 | var->lower_margin = display->lower_margin; | ||
216 | var->vsync_len = display->vsync_len; | ||
217 | var->hsync_len = display->hsync_len; | ||
218 | |||
219 | fbi->regs.lcdcon5 = display->lcdcon5; | ||
220 | /* set display type */ | ||
221 | fbi->regs.lcdcon1 = display->type; | ||
222 | |||
223 | var->transp.offset = 0; | ||
224 | var->transp.length = 0; | ||
201 | /* set r/g/b positions */ | 225 | /* set r/g/b positions */ |
202 | switch (var->bits_per_pixel) { | 226 | switch (var->bits_per_pixel) { |
203 | case 1: | 227 | case 1: |
204 | case 2: | 228 | case 2: |
205 | case 4: | 229 | case 4: |
206 | var->red.offset = 0; | 230 | var->red.offset = 0; |
207 | var->red.length = var->bits_per_pixel; | 231 | var->red.length = var->bits_per_pixel; |
208 | var->green = var->red; | 232 | var->green = var->red; |
209 | var->blue = var->red; | 233 | var->blue = var->red; |
210 | var->transp.offset = 0; | 234 | break; |
211 | var->transp.length = 0; | 235 | case 8: |
212 | break; | 236 | if (display->type != S3C2410_LCDCON1_TFT) { |
213 | case 8: | 237 | /* 8 bpp 332 */ |
214 | if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) { | 238 | var->red.length = 3; |
215 | /* 8 bpp 332 */ | 239 | var->red.offset = 5; |
216 | var->red.length = 3; | 240 | var->green.length = 3; |
217 | var->red.offset = 5; | 241 | var->green.offset = 2; |
218 | var->green.length = 3; | 242 | var->blue.length = 2; |
219 | var->green.offset = 2; | ||
220 | var->blue.length = 2; | ||
221 | var->blue.offset = 0; | ||
222 | var->transp.length = 0; | ||
223 | } else { | ||
224 | var->red.offset = 0; | ||
225 | var->red.length = var->bits_per_pixel; | ||
226 | var->green = var->red; | ||
227 | var->blue = var->red; | ||
228 | var->transp.offset = 0; | ||
229 | var->transp.length = 0; | ||
230 | } | ||
231 | break; | ||
232 | case 12: | ||
233 | /* 12 bpp 444 */ | ||
234 | var->red.length = 4; | ||
235 | var->red.offset = 8; | ||
236 | var->green.length = 4; | ||
237 | var->green.offset = 4; | ||
238 | var->blue.length = 4; | ||
239 | var->blue.offset = 0; | 243 | var->blue.offset = 0; |
240 | var->transp.length = 0; | 244 | } else { |
241 | break; | 245 | var->red.offset = 0; |
242 | |||
243 | default: | ||
244 | case 16: | ||
245 | if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) { | ||
246 | /* 16 bpp, 565 format */ | ||
247 | var->red.offset = 11; | ||
248 | var->green.offset = 5; | ||
249 | var->blue.offset = 0; | ||
250 | var->red.length = 5; | ||
251 | var->green.length = 6; | ||
252 | var->blue.length = 5; | ||
253 | var->transp.length = 0; | ||
254 | } else { | ||
255 | /* 16 bpp, 5551 format */ | ||
256 | var->red.offset = 11; | ||
257 | var->green.offset = 6; | ||
258 | var->blue.offset = 1; | ||
259 | var->red.length = 5; | ||
260 | var->green.length = 5; | ||
261 | var->blue.length = 5; | ||
262 | var->transp.length = 0; | ||
263 | } | ||
264 | break; | ||
265 | case 24: | ||
266 | /* 24 bpp 888 */ | ||
267 | var->red.length = 8; | 246 | var->red.length = 8; |
268 | var->red.offset = 16; | 247 | var->green = var->red; |
269 | var->green.length = 8; | 248 | var->blue = var->red; |
270 | var->green.offset = 8; | 249 | } |
271 | var->blue.length = 8; | 250 | break; |
272 | var->blue.offset = 0; | 251 | case 12: |
273 | var->transp.length = 0; | 252 | /* 12 bpp 444 */ |
274 | break; | 253 | var->red.length = 4; |
275 | 254 | var->red.offset = 8; | |
255 | var->green.length = 4; | ||
256 | var->green.offset = 4; | ||
257 | var->blue.length = 4; | ||
258 | var->blue.offset = 0; | ||
259 | break; | ||
276 | 260 | ||
261 | default: | ||
262 | case 16: | ||
263 | if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) { | ||
264 | /* 16 bpp, 565 format */ | ||
265 | var->red.offset = 11; | ||
266 | var->green.offset = 5; | ||
267 | var->blue.offset = 0; | ||
268 | var->red.length = 5; | ||
269 | var->green.length = 6; | ||
270 | var->blue.length = 5; | ||
271 | } else { | ||
272 | /* 16 bpp, 5551 format */ | ||
273 | var->red.offset = 11; | ||
274 | var->green.offset = 6; | ||
275 | var->blue.offset = 1; | ||
276 | var->red.length = 5; | ||
277 | var->green.length = 5; | ||
278 | var->blue.length = 5; | ||
279 | } | ||
280 | break; | ||
281 | case 32: | ||
282 | /* 24 bpp 888 and 8 dummy */ | ||
283 | var->red.length = 8; | ||
284 | var->red.offset = 16; | ||
285 | var->green.length = 8; | ||
286 | var->green.offset = 8; | ||
287 | var->blue.length = 8; | ||
288 | var->blue.offset = 0; | ||
289 | break; | ||
277 | } | 290 | } |
278 | return 0; | 291 | return 0; |
279 | } | 292 | } |
280 | 293 | ||
281 | 294 | /* s3c2410fb_calculate_stn_lcd_regs | |
282 | /* s3c2410fb_activate_var | ||
283 | * | 295 | * |
284 | * activate (set) the controller from the given framebuffer | 296 | * calculate register values from var settings |
285 | * information | 297 | */ |
286 | */ | 298 | static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info, |
287 | 299 | struct s3c2410fb_hw *regs) | |
288 | static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, | ||
289 | struct fb_var_screeninfo *var) | ||
290 | { | 300 | { |
291 | int hs; | 301 | const struct s3c2410fb_info *fbi = info->par; |
302 | const struct fb_var_screeninfo *var = &info->var; | ||
303 | int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT; | ||
304 | int hs = var->xres >> 2; | ||
305 | unsigned wdly = (var->left_margin >> 4) - 1; | ||
306 | unsigned wlh = (var->hsync_len >> 4) - 1; | ||
292 | 307 | ||
293 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; | 308 | if (type != S3C2410_LCDCON1_STN4) |
294 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT; | 309 | hs >>= 1; |
295 | 310 | ||
296 | dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); | 311 | switch (var->bits_per_pixel) { |
297 | dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); | 312 | case 1: |
298 | dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); | 313 | regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP; |
314 | break; | ||
315 | case 2: | ||
316 | regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY; | ||
317 | break; | ||
318 | case 4: | ||
319 | regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY; | ||
320 | break; | ||
321 | case 8: | ||
322 | regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP; | ||
323 | hs *= 3; | ||
324 | break; | ||
325 | case 12: | ||
326 | regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP; | ||
327 | hs *= 3; | ||
328 | break; | ||
299 | 329 | ||
300 | fbi->regs.lcdcon1 |= fbi->mach_info->type; | 330 | default: |
301 | 331 | /* invalid pixel depth */ | |
302 | if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) | 332 | dev_err(fbi->dev, "invalid bpp %d\n", |
303 | switch (var->bits_per_pixel) { | 333 | var->bits_per_pixel); |
304 | case 1: | 334 | } |
305 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; | 335 | /* update X/Y info */ |
306 | break; | 336 | dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", |
307 | case 2: | 337 | var->left_margin, var->right_margin, var->hsync_len); |
308 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; | ||
309 | break; | ||
310 | case 4: | ||
311 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; | ||
312 | break; | ||
313 | case 8: | ||
314 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; | ||
315 | break; | ||
316 | case 16: | ||
317 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | /* invalid pixel depth */ | ||
322 | dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); | ||
323 | } | ||
324 | else | ||
325 | switch (var->bits_per_pixel) { | ||
326 | case 1: | ||
327 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP; | ||
328 | break; | ||
329 | case 2: | ||
330 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY; | ||
331 | break; | ||
332 | case 4: | ||
333 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY; | ||
334 | break; | ||
335 | case 8: | ||
336 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP; | ||
337 | break; | ||
338 | case 12: | ||
339 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP; | ||
340 | break; | ||
341 | |||
342 | default: | ||
343 | /* invalid pixel depth */ | ||
344 | dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); | ||
345 | } | ||
346 | 338 | ||
347 | /* check to see if we need to update sync/borders */ | 339 | regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1); |
348 | 340 | ||
349 | if (!fbi->mach_info->fixed_syncs) { | 341 | if (wdly > 3) |
350 | dprintk("setting vert: up=%d, low=%d, sync=%d\n", | 342 | wdly = 3; |
351 | var->upper_margin, var->lower_margin, | ||
352 | var->vsync_len); | ||
353 | 343 | ||
354 | dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", | 344 | if (wlh > 3) |
355 | var->left_margin, var->right_margin, | 345 | wlh = 3; |
356 | var->hsync_len); | ||
357 | 346 | ||
358 | fbi->regs.lcdcon2 = | 347 | regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) | |
359 | S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | | 348 | S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) | |
360 | S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | | 349 | S3C2410_LCDCON3_HOZVAL(hs - 1); |
361 | S3C2410_LCDCON2_VSPW(var->vsync_len - 1); | ||
362 | 350 | ||
363 | fbi->regs.lcdcon3 = | 351 | regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh); |
364 | S3C2410_LCDCON3_HBPD(var->right_margin - 1) | | 352 | } |
365 | S3C2410_LCDCON3_HFPD(var->left_margin - 1); | ||
366 | 353 | ||
367 | fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff); | 354 | /* s3c2410fb_calculate_tft_lcd_regs |
368 | fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1); | 355 | * |
369 | } | 356 | * calculate register values from var settings |
357 | */ | ||
358 | static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info, | ||
359 | struct s3c2410fb_hw *regs) | ||
360 | { | ||
361 | const struct s3c2410fb_info *fbi = info->par; | ||
362 | const struct fb_var_screeninfo *var = &info->var; | ||
370 | 363 | ||
364 | switch (var->bits_per_pixel) { | ||
365 | case 1: | ||
366 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; | ||
367 | break; | ||
368 | case 2: | ||
369 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; | ||
370 | break; | ||
371 | case 4: | ||
372 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; | ||
373 | break; | ||
374 | case 8: | ||
375 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; | ||
376 | regs->lcdcon5 |= S3C2410_LCDCON5_BSWP | | ||
377 | S3C2410_LCDCON5_FRM565; | ||
378 | regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP; | ||
379 | break; | ||
380 | case 16: | ||
381 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; | ||
382 | regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP; | ||
383 | regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP; | ||
384 | break; | ||
385 | case 32: | ||
386 | regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP; | ||
387 | regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP | | ||
388 | S3C2410_LCDCON5_HWSWP | | ||
389 | S3C2410_LCDCON5_BPP24BL); | ||
390 | break; | ||
391 | default: | ||
392 | /* invalid pixel depth */ | ||
393 | dev_err(fbi->dev, "invalid bpp %d\n", | ||
394 | var->bits_per_pixel); | ||
395 | } | ||
371 | /* update X/Y info */ | 396 | /* update X/Y info */ |
397 | dprintk("setting vert: up=%d, low=%d, sync=%d\n", | ||
398 | var->upper_margin, var->lower_margin, var->vsync_len); | ||
372 | 399 | ||
373 | fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); | 400 | dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", |
374 | fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); | 401 | var->left_margin, var->right_margin, var->hsync_len); |
375 | |||
376 | switch(fbi->mach_info->type) { | ||
377 | case S3C2410_LCDCON1_DSCAN4: | ||
378 | case S3C2410_LCDCON1_STN8: | ||
379 | hs = var->xres / 8; | ||
380 | break; | ||
381 | case S3C2410_LCDCON1_STN4: | ||
382 | hs = var->xres / 4; | ||
383 | break; | ||
384 | default: | ||
385 | case S3C2410_LCDCON1_TFT: | ||
386 | hs = var->xres; | ||
387 | break; | ||
388 | |||
389 | } | ||
390 | 402 | ||
391 | /* Special cases : STN color displays */ | 403 | regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) | |
392 | if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \ | 404 | S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | |
393 | || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) { | 405 | S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | |
394 | hs = hs * 3; | 406 | S3C2410_LCDCON2_VSPW(var->vsync_len - 1); |
395 | } | ||
396 | 407 | ||
408 | regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) | | ||
409 | S3C2410_LCDCON3_HFPD(var->left_margin - 1) | | ||
410 | S3C2410_LCDCON3_HOZVAL(var->xres - 1); | ||
397 | 411 | ||
398 | fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); | 412 | regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1); |
399 | fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1); | 413 | } |
400 | 414 | ||
401 | if (var->pixclock > 0) { | 415 | /* s3c2410fb_activate_var |
402 | int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); | 416 | * |
417 | * activate (set) the controller from the given framebuffer | ||
418 | * information | ||
419 | */ | ||
420 | static void s3c2410fb_activate_var(struct fb_info *info) | ||
421 | { | ||
422 | struct s3c2410fb_info *fbi = info->par; | ||
423 | void __iomem *regs = fbi->io; | ||
424 | int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; | ||
425 | struct fb_var_screeninfo *var = &info->var; | ||
426 | int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2; | ||
403 | 427 | ||
404 | if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) { | 428 | dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); |
405 | clkdiv = (clkdiv / 2) -1; | 429 | dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); |
406 | if (clkdiv < 0) | 430 | dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); |
407 | clkdiv = 0; | ||
408 | } | ||
409 | else { | ||
410 | clkdiv = (clkdiv / 2); | ||
411 | if (clkdiv < 2) | ||
412 | clkdiv = 2; | ||
413 | } | ||
414 | 431 | ||
415 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); | 432 | if (type == S3C2410_LCDCON1_TFT) { |
416 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); | 433 | s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); |
434 | --clkdiv; | ||
435 | if (clkdiv < 0) | ||
436 | clkdiv = 0; | ||
437 | } else { | ||
438 | s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs); | ||
439 | if (clkdiv < 2) | ||
440 | clkdiv = 2; | ||
417 | } | 441 | } |
418 | 442 | ||
443 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); | ||
444 | |||
419 | /* write new registers */ | 445 | /* write new registers */ |
420 | 446 | ||
421 | dprintk("new register set:\n"); | 447 | dprintk("new register set:\n"); |
@@ -425,47 +451,48 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, | |||
425 | dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); | 451 | dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); |
426 | dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); | 452 | dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); |
427 | 453 | ||
428 | writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); | 454 | writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, |
429 | writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); | 455 | regs + S3C2410_LCDCON1); |
430 | writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); | 456 | writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2); |
431 | writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); | 457 | writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3); |
432 | writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); | 458 | writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4); |
459 | writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5); | ||
433 | 460 | ||
434 | /* set lcd address pointers */ | 461 | /* set lcd address pointers */ |
435 | s3c2410fb_set_lcdaddr(fbi); | 462 | s3c2410fb_set_lcdaddr(info); |
436 | 463 | ||
437 | writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); | 464 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID, |
465 | writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); | ||
438 | } | 466 | } |
439 | 467 | ||
440 | |||
441 | /* | 468 | /* |
442 | * s3c2410fb_set_par - Optional function. Alters the hardware state. | 469 | * s3c2410fb_set_par - Alters the hardware state. |
443 | * @info: frame buffer structure that represents a single frame buffer | 470 | * @info: frame buffer structure that represents a single frame buffer |
444 | * | 471 | * |
445 | */ | 472 | */ |
446 | static int s3c2410fb_set_par(struct fb_info *info) | 473 | static int s3c2410fb_set_par(struct fb_info *info) |
447 | { | 474 | { |
448 | struct s3c2410fb_info *fbi = info->par; | ||
449 | struct fb_var_screeninfo *var = &info->var; | 475 | struct fb_var_screeninfo *var = &info->var; |
450 | 476 | ||
451 | switch (var->bits_per_pixel) | 477 | switch (var->bits_per_pixel) { |
452 | { | 478 | case 32: |
453 | case 16: | 479 | case 16: |
454 | fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; | 480 | case 12: |
455 | break; | 481 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
456 | case 1: | 482 | break; |
457 | fbi->fb->fix.visual = FB_VISUAL_MONO01; | 483 | case 1: |
458 | break; | 484 | info->fix.visual = FB_VISUAL_MONO01; |
459 | default: | 485 | break; |
460 | fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 486 | default: |
461 | break; | 487 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
488 | break; | ||
462 | } | 489 | } |
463 | 490 | ||
464 | fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; | 491 | info->fix.line_length = (var->width * var->bits_per_pixel) / 8; |
465 | 492 | ||
466 | /* activate this new configuration */ | 493 | /* activate this new configuration */ |
467 | 494 | ||
468 | s3c2410fb_activate_var(fbi, var); | 495 | s3c2410fb_activate_var(info); |
469 | return 0; | 496 | return 0; |
470 | } | 497 | } |
471 | 498 | ||
@@ -493,7 +520,8 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, | |||
493 | } | 520 | } |
494 | 521 | ||
495 | /* from pxafb.c */ | 522 | /* from pxafb.c */ |
496 | static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) | 523 | static inline unsigned int chan_to_field(unsigned int chan, |
524 | struct fb_bitfield *bf) | ||
497 | { | 525 | { |
498 | chan &= 0xffff; | 526 | chan &= 0xffff; |
499 | chan >>= 16 - bf->length; | 527 | chan >>= 16 - bf->length; |
@@ -505,20 +533,22 @@ static int s3c2410fb_setcolreg(unsigned regno, | |||
505 | unsigned transp, struct fb_info *info) | 533 | unsigned transp, struct fb_info *info) |
506 | { | 534 | { |
507 | struct s3c2410fb_info *fbi = info->par; | 535 | struct s3c2410fb_info *fbi = info->par; |
536 | void __iomem *regs = fbi->io; | ||
508 | unsigned int val; | 537 | unsigned int val; |
509 | 538 | ||
510 | /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */ | 539 | /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", |
540 | regno, red, green, blue); */ | ||
511 | 541 | ||
512 | switch (fbi->fb->fix.visual) { | 542 | switch (info->fix.visual) { |
513 | case FB_VISUAL_TRUECOLOR: | 543 | case FB_VISUAL_TRUECOLOR: |
514 | /* true-colour, use pseuo-palette */ | 544 | /* true-colour, use pseudo-palette */ |
515 | 545 | ||
516 | if (regno < 16) { | 546 | if (regno < 16) { |
517 | u32 *pal = fbi->fb->pseudo_palette; | 547 | u32 *pal = info->pseudo_palette; |
518 | 548 | ||
519 | val = chan_to_field(red, &fbi->fb->var.red); | 549 | val = chan_to_field(red, &info->var.red); |
520 | val |= chan_to_field(green, &fbi->fb->var.green); | 550 | val |= chan_to_field(green, &info->var.green); |
521 | val |= chan_to_field(blue, &fbi->fb->var.blue); | 551 | val |= chan_to_field(blue, &info->var.blue); |
522 | 552 | ||
523 | pal[regno] = val; | 553 | pal[regno] = val; |
524 | } | 554 | } |
@@ -528,25 +558,24 @@ static int s3c2410fb_setcolreg(unsigned regno, | |||
528 | if (regno < 256) { | 558 | if (regno < 256) { |
529 | /* currently assume RGB 5-6-5 mode */ | 559 | /* currently assume RGB 5-6-5 mode */ |
530 | 560 | ||
531 | val = ((red >> 0) & 0xf800); | 561 | val = (red >> 0) & 0xf800; |
532 | val |= ((green >> 5) & 0x07e0); | 562 | val |= (green >> 5) & 0x07e0; |
533 | val |= ((blue >> 11) & 0x001f); | 563 | val |= (blue >> 11) & 0x001f; |
534 | 564 | ||
535 | writel(val, S3C2410_TFTPAL(regno)); | 565 | writel(val, regs + S3C2410_TFTPAL(regno)); |
536 | schedule_palette_update(fbi, regno, val); | 566 | schedule_palette_update(fbi, regno, val); |
537 | } | 567 | } |
538 | 568 | ||
539 | break; | 569 | break; |
540 | 570 | ||
541 | default: | 571 | default: |
542 | return 1; /* unknown type */ | 572 | return 1; /* unknown type */ |
543 | } | 573 | } |
544 | 574 | ||
545 | return 0; | 575 | return 0; |
546 | } | 576 | } |
547 | 577 | ||
548 | 578 | /* | |
549 | /** | ||
550 | * s3c2410fb_blank | 579 | * s3c2410fb_blank |
551 | * @blank_mode: the blank mode we want. | 580 | * @blank_mode: the blank mode we want. |
552 | * @info: frame buffer structure that represents a single frame buffer | 581 | * @info: frame buffer structure that represents a single frame buffer |
@@ -564,31 +593,31 @@ static int s3c2410fb_setcolreg(unsigned regno, | |||
564 | */ | 593 | */ |
565 | static int s3c2410fb_blank(int blank_mode, struct fb_info *info) | 594 | static int s3c2410fb_blank(int blank_mode, struct fb_info *info) |
566 | { | 595 | { |
567 | dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); | 596 | struct s3c2410fb_info *fbi = info->par; |
597 | void __iomem *regs = fbi->io; | ||
568 | 598 | ||
569 | if (mach_info == NULL) | 599 | dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); |
570 | return -EINVAL; | ||
571 | 600 | ||
572 | if (blank_mode == FB_BLANK_UNBLANK) | 601 | if (blank_mode == FB_BLANK_UNBLANK) |
573 | writel(0x0, S3C2410_TPAL); | 602 | writel(0x0, regs + S3C2410_TPAL); |
574 | else { | 603 | else { |
575 | dprintk("setting TPAL to output 0x000000\n"); | 604 | dprintk("setting TPAL to output 0x000000\n"); |
576 | writel(S3C2410_TPAL_EN, S3C2410_TPAL); | 605 | writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL); |
577 | } | 606 | } |
578 | 607 | ||
579 | return 0; | 608 | return 0; |
580 | } | 609 | } |
581 | 610 | ||
582 | static int s3c2410fb_debug_show(struct device *dev, struct device_attribute *attr, char *buf) | 611 | static int s3c2410fb_debug_show(struct device *dev, |
612 | struct device_attribute *attr, char *buf) | ||
583 | { | 613 | { |
584 | return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); | 614 | return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); |
585 | } | 615 | } |
586 | static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *attr, | ||
587 | const char *buf, size_t len) | ||
588 | { | ||
589 | if (mach_info == NULL) | ||
590 | return -EINVAL; | ||
591 | 616 | ||
617 | static int s3c2410fb_debug_store(struct device *dev, | ||
618 | struct device_attribute *attr, | ||
619 | const char *buf, size_t len) | ||
620 | { | ||
592 | if (len < 1) | 621 | if (len < 1) |
593 | return -EINVAL; | 622 | return -EINVAL; |
594 | 623 | ||
@@ -607,10 +636,7 @@ static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *at | |||
607 | return len; | 636 | return len; |
608 | } | 637 | } |
609 | 638 | ||
610 | 639 | static DEVICE_ATTR(debug, 0666, s3c2410fb_debug_show, s3c2410fb_debug_store); | |
611 | static DEVICE_ATTR(debug, 0666, | ||
612 | s3c2410fb_debug_show, | ||
613 | s3c2410fb_debug_store); | ||
614 | 640 | ||
615 | static struct fb_ops s3c2410fb_ops = { | 641 | static struct fb_ops s3c2410fb_ops = { |
616 | .owner = THIS_MODULE, | 642 | .owner = THIS_MODULE, |
@@ -623,7 +649,6 @@ static struct fb_ops s3c2410fb_ops = { | |||
623 | .fb_imageblit = cfb_imageblit, | 649 | .fb_imageblit = cfb_imageblit, |
624 | }; | 650 | }; |
625 | 651 | ||
626 | |||
627 | /* | 652 | /* |
628 | * s3c2410fb_map_video_memory(): | 653 | * s3c2410fb_map_video_memory(): |
629 | * Allocates the DRAM memory for the frame buffer. This buffer is | 654 | * Allocates the DRAM memory for the frame buffer. This buffer is |
@@ -632,36 +657,38 @@ static struct fb_ops s3c2410fb_ops = { | |||
632 | * cache. Once this area is remapped, all virtual memory | 657 | * cache. Once this area is remapped, all virtual memory |
633 | * access to the video memory should occur at the new region. | 658 | * access to the video memory should occur at the new region. |
634 | */ | 659 | */ |
635 | static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi) | 660 | static int __init s3c2410fb_map_video_memory(struct fb_info *info) |
636 | { | 661 | { |
637 | dprintk("map_video_memory(fbi=%p)\n", fbi); | 662 | struct s3c2410fb_info *fbi = info->par; |
663 | dma_addr_t map_dma; | ||
664 | unsigned map_size = PAGE_ALIGN(info->fix.smem_len); | ||
638 | 665 | ||
639 | fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE); | 666 | dprintk("map_video_memory(fbi=%p)\n", fbi); |
640 | fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, | ||
641 | &fbi->map_dma, GFP_KERNEL); | ||
642 | 667 | ||
643 | fbi->map_size = fbi->fb->fix.smem_len; | 668 | info->screen_base = dma_alloc_writecombine(fbi->dev, map_size, |
669 | &map_dma, GFP_KERNEL); | ||
644 | 670 | ||
645 | if (fbi->map_cpu) { | 671 | if (info->screen_base) { |
646 | /* prevent initial garbage on screen */ | 672 | /* prevent initial garbage on screen */ |
647 | dprintk("map_video_memory: clear %p:%08x\n", | 673 | dprintk("map_video_memory: clear %p:%08x\n", |
648 | fbi->map_cpu, fbi->map_size); | 674 | info->screen_base, map_size); |
649 | memset(fbi->map_cpu, 0xf0, fbi->map_size); | 675 | memset(info->screen_base, 0xf0, map_size); |
650 | 676 | ||
651 | fbi->screen_dma = fbi->map_dma; | 677 | info->fix.smem_start = map_dma; |
652 | fbi->fb->screen_base = fbi->map_cpu; | ||
653 | fbi->fb->fix.smem_start = fbi->screen_dma; | ||
654 | 678 | ||
655 | dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n", | 679 | dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n", |
656 | fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len); | 680 | info->fix.smem_start, info->screen_base, map_size); |
657 | } | 681 | } |
658 | 682 | ||
659 | return fbi->map_cpu ? 0 : -ENOMEM; | 683 | return info->screen_base ? 0 : -ENOMEM; |
660 | } | 684 | } |
661 | 685 | ||
662 | static inline void s3c2410fb_unmap_video_memory(struct s3c2410fb_info *fbi) | 686 | static inline void s3c2410fb_unmap_video_memory(struct fb_info *info) |
663 | { | 687 | { |
664 | dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); | 688 | struct s3c2410fb_info *fbi = info->par; |
689 | |||
690 | dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len), | ||
691 | info->screen_base, info->fix.smem_start); | ||
665 | } | 692 | } |
666 | 693 | ||
667 | static inline void modify_gpio(void __iomem *reg, | 694 | static inline void modify_gpio(void __iomem *reg, |
@@ -673,13 +700,13 @@ static inline void modify_gpio(void __iomem *reg, | |||
673 | writel(tmp | set, reg); | 700 | writel(tmp | set, reg); |
674 | } | 701 | } |
675 | 702 | ||
676 | |||
677 | /* | 703 | /* |
678 | * s3c2410fb_init_registers - Initialise all LCD-related registers | 704 | * s3c2410fb_init_registers - Initialise all LCD-related registers |
679 | */ | 705 | */ |
680 | 706 | static int s3c2410fb_init_registers(struct fb_info *info) | |
681 | static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) | ||
682 | { | 707 | { |
708 | struct s3c2410fb_info *fbi = info->par; | ||
709 | struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; | ||
683 | unsigned long flags; | 710 | unsigned long flags; |
684 | void __iomem *regs = fbi->io; | 711 | void __iomem *regs = fbi->io; |
685 | 712 | ||
@@ -696,14 +723,6 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) | |||
696 | 723 | ||
697 | local_irq_restore(flags); | 724 | local_irq_restore(flags); |
698 | 725 | ||
699 | writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); | ||
700 | writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2); | ||
701 | writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3); | ||
702 | writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4); | ||
703 | writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5); | ||
704 | |||
705 | s3c2410fb_set_lcdaddr(fbi); | ||
706 | |||
707 | dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); | 726 | dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); |
708 | writel(mach_info->lpcsel, regs + S3C2410_LPCSEL); | 727 | writel(mach_info->lpcsel, regs + S3C2410_LPCSEL); |
709 | 728 | ||
@@ -712,22 +731,19 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) | |||
712 | /* ensure temporary palette disabled */ | 731 | /* ensure temporary palette disabled */ |
713 | writel(0x00, regs + S3C2410_TPAL); | 732 | writel(0x00, regs + S3C2410_TPAL); |
714 | 733 | ||
715 | /* Enable video by setting the ENVID bit to 1 */ | ||
716 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; | ||
717 | writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); | ||
718 | return 0; | 734 | return 0; |
719 | } | 735 | } |
720 | 736 | ||
721 | static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) | 737 | static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) |
722 | { | 738 | { |
723 | unsigned int i; | 739 | unsigned int i; |
724 | unsigned long ent; | ||
725 | void __iomem *regs = fbi->io; | 740 | void __iomem *regs = fbi->io; |
726 | 741 | ||
727 | fbi->palette_ready = 0; | 742 | fbi->palette_ready = 0; |
728 | 743 | ||
729 | for (i = 0; i < 256; i++) { | 744 | for (i = 0; i < 256; i++) { |
730 | if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR) | 745 | unsigned long ent = fbi->palette_buffer[i]; |
746 | if (ent == PALETTE_BUFF_CLEAR) | ||
731 | continue; | 747 | continue; |
732 | 748 | ||
733 | writel(ent, regs + S3C2410_TFTPAL(i)); | 749 | writel(ent, regs + S3C2410_TFTPAL(i)); |
@@ -761,13 +777,14 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) | |||
761 | return IRQ_HANDLED; | 777 | return IRQ_HANDLED; |
762 | } | 778 | } |
763 | 779 | ||
764 | static char driver_name[]="s3c2410fb"; | 780 | static char driver_name[] = "s3c2410fb"; |
765 | 781 | ||
766 | static int __init s3c2410fb_probe(struct platform_device *pdev) | 782 | static int __init s3c2410fb_probe(struct platform_device *pdev) |
767 | { | 783 | { |
768 | struct s3c2410fb_info *info; | 784 | struct s3c2410fb_info *info; |
769 | struct fb_info *fbinfo; | 785 | struct s3c2410fb_display *display; |
770 | struct s3c2410fb_hw *mregs; | 786 | struct fb_info *fbinfo; |
787 | struct s3c2410fb_mach_info *mach_info; | ||
771 | struct resource *res; | 788 | struct resource *res; |
772 | int ret; | 789 | int ret; |
773 | int irq; | 790 | int irq; |
@@ -777,11 +794,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
777 | 794 | ||
778 | mach_info = pdev->dev.platform_data; | 795 | mach_info = pdev->dev.platform_data; |
779 | if (mach_info == NULL) { | 796 | if (mach_info == NULL) { |
780 | dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n"); | 797 | dev_err(&pdev->dev, |
798 | "no platform data for lcd, cannot attach\n"); | ||
781 | return -EINVAL; | 799 | return -EINVAL; |
782 | } | 800 | } |
783 | 801 | ||
784 | mregs = &mach_info->regs; | 802 | display = mach_info->displays + mach_info->default_display; |
785 | 803 | ||
786 | irq = platform_get_irq(pdev, 0); | 804 | irq = platform_get_irq(pdev, 0); |
787 | if (irq < 0) { | 805 | if (irq < 0) { |
@@ -790,22 +808,22 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
790 | } | 808 | } |
791 | 809 | ||
792 | fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); | 810 | fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); |
793 | if (!fbinfo) { | 811 | if (!fbinfo) |
794 | return -ENOMEM; | 812 | return -ENOMEM; |
795 | } | 813 | |
814 | platform_set_drvdata(pdev, fbinfo); | ||
796 | 815 | ||
797 | info = fbinfo->par; | 816 | info = fbinfo->par; |
798 | info->fb = fbinfo; | ||
799 | info->dev = &pdev->dev; | 817 | info->dev = &pdev->dev; |
800 | 818 | ||
801 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 819 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
802 | if (res == NULL) { | 820 | if (res == NULL) { |
803 | dev_err(&pdev->dev, "failed to get memory registersn"); | 821 | dev_err(&pdev->dev, "failed to get memory registers\n"); |
804 | ret = -ENXIO; | 822 | ret = -ENXIO; |
805 | goto dealloc_fb; | 823 | goto dealloc_fb; |
806 | } | 824 | } |
807 | 825 | ||
808 | size = (res->end - res->start)+1; | 826 | size = (res->end - res->start) + 1; |
809 | info->mem = request_mem_region(res->start, size, pdev->name); | 827 | info->mem = request_mem_region(res->start, size, pdev->name); |
810 | if (info->mem == NULL) { | 828 | if (info->mem == NULL) { |
811 | dev_err(&pdev->dev, "failed to get memory region\n"); | 829 | dev_err(&pdev->dev, "failed to get memory region\n"); |
@@ -820,21 +838,14 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
820 | goto release_mem; | 838 | goto release_mem; |
821 | } | 839 | } |
822 | 840 | ||
823 | platform_set_drvdata(pdev, fbinfo); | ||
824 | |||
825 | dprintk("devinit\n"); | 841 | dprintk("devinit\n"); |
826 | 842 | ||
827 | strcpy(fbinfo->fix.id, driver_name); | 843 | strcpy(fbinfo->fix.id, driver_name); |
828 | 844 | ||
829 | memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); | 845 | /* Stop the video */ |
830 | |||
831 | /* Stop the video and unset ENVID if set */ | ||
832 | info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; | ||
833 | lcdcon1 = readl(info->io + S3C2410_LCDCON1); | 846 | lcdcon1 = readl(info->io + S3C2410_LCDCON1); |
834 | writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); | 847 | writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); |
835 | 848 | ||
836 | info->mach_info = pdev->dev.platform_data; | ||
837 | |||
838 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 849 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
839 | fbinfo->fix.type_aux = 0; | 850 | fbinfo->fix.type_aux = 0; |
840 | fbinfo->fix.xpanstep = 0; | 851 | fbinfo->fix.xpanstep = 0; |
@@ -844,8 +855,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
844 | 855 | ||
845 | fbinfo->var.nonstd = 0; | 856 | fbinfo->var.nonstd = 0; |
846 | fbinfo->var.activate = FB_ACTIVATE_NOW; | 857 | fbinfo->var.activate = FB_ACTIVATE_NOW; |
847 | fbinfo->var.height = mach_info->height; | ||
848 | fbinfo->var.width = mach_info->width; | ||
849 | fbinfo->var.accel_flags = 0; | 858 | fbinfo->var.accel_flags = 0; |
850 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; | 859 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; |
851 | 860 | ||
@@ -853,32 +862,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
853 | fbinfo->flags = FBINFO_FLAG_DEFAULT; | 862 | fbinfo->flags = FBINFO_FLAG_DEFAULT; |
854 | fbinfo->pseudo_palette = &info->pseudo_pal; | 863 | fbinfo->pseudo_palette = &info->pseudo_pal; |
855 | 864 | ||
856 | fbinfo->var.xres = mach_info->xres.defval; | ||
857 | fbinfo->var.xres_virtual = mach_info->xres.defval; | ||
858 | fbinfo->var.yres = mach_info->yres.defval; | ||
859 | fbinfo->var.yres_virtual = mach_info->yres.defval; | ||
860 | fbinfo->var.bits_per_pixel = mach_info->bpp.defval; | ||
861 | |||
862 | fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1; | ||
863 | fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) + 1; | ||
864 | fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1; | ||
865 | |||
866 | fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1; | ||
867 | fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1; | ||
868 | fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1; | ||
869 | |||
870 | fbinfo->var.red.offset = 11; | ||
871 | fbinfo->var.green.offset = 5; | ||
872 | fbinfo->var.blue.offset = 0; | ||
873 | fbinfo->var.transp.offset = 0; | ||
874 | fbinfo->var.red.length = 5; | ||
875 | fbinfo->var.green.length = 6; | ||
876 | fbinfo->var.blue.length = 5; | ||
877 | fbinfo->var.transp.length = 0; | ||
878 | fbinfo->fix.smem_len = mach_info->xres.max * | ||
879 | mach_info->yres.max * | ||
880 | mach_info->bpp.max / 8; | ||
881 | |||
882 | for (i = 0; i < 256; i++) | 865 | for (i = 0; i < 256; i++) |
883 | info->palette_buffer[i] = PALETTE_BUFF_CLEAR; | 866 | info->palette_buffer[i] = PALETTE_BUFF_CLEAR; |
884 | 867 | ||
@@ -901,23 +884,39 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
901 | 884 | ||
902 | msleep(1); | 885 | msleep(1); |
903 | 886 | ||
887 | /* find maximum required memory size for display */ | ||
888 | for (i = 0; i < mach_info->num_displays; i++) { | ||
889 | unsigned long smem_len = mach_info->displays[i].xres; | ||
890 | |||
891 | smem_len *= mach_info->displays[i].yres; | ||
892 | smem_len *= mach_info->displays[i].bpp; | ||
893 | smem_len >>= 3; | ||
894 | if (fbinfo->fix.smem_len < smem_len) | ||
895 | fbinfo->fix.smem_len = smem_len; | ||
896 | } | ||
897 | |||
904 | /* Initialize video memory */ | 898 | /* Initialize video memory */ |
905 | ret = s3c2410fb_map_video_memory(info); | 899 | ret = s3c2410fb_map_video_memory(fbinfo); |
906 | if (ret) { | 900 | if (ret) { |
907 | printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret); | 901 | printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret); |
908 | ret = -ENOMEM; | 902 | ret = -ENOMEM; |
909 | goto release_clock; | 903 | goto release_clock; |
910 | } | 904 | } |
911 | 905 | ||
912 | dprintk("got video memory\n"); | 906 | dprintk("got video memory\n"); |
913 | 907 | ||
914 | ret = s3c2410fb_init_registers(info); | 908 | fbinfo->var.xres = display->xres; |
909 | fbinfo->var.yres = display->yres; | ||
910 | fbinfo->var.bits_per_pixel = display->bpp; | ||
911 | |||
912 | s3c2410fb_init_registers(fbinfo); | ||
915 | 913 | ||
916 | ret = s3c2410fb_check_var(&fbinfo->var, fbinfo); | 914 | s3c2410fb_check_var(&fbinfo->var, fbinfo); |
917 | 915 | ||
918 | ret = register_framebuffer(fbinfo); | 916 | ret = register_framebuffer(fbinfo); |
919 | if (ret < 0) { | 917 | if (ret < 0) { |
920 | printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret); | 918 | printk(KERN_ERR "Failed to register framebuffer device: %d\n", |
919 | ret); | ||
921 | goto free_video_memory; | 920 | goto free_video_memory; |
922 | } | 921 | } |
923 | 922 | ||
@@ -930,18 +929,19 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
930 | return 0; | 929 | return 0; |
931 | 930 | ||
932 | free_video_memory: | 931 | free_video_memory: |
933 | s3c2410fb_unmap_video_memory(info); | 932 | s3c2410fb_unmap_video_memory(fbinfo); |
934 | release_clock: | 933 | release_clock: |
935 | clk_disable(info->clk); | 934 | clk_disable(info->clk); |
936 | clk_put(info->clk); | 935 | clk_put(info->clk); |
937 | release_irq: | 936 | release_irq: |
938 | free_irq(irq,info); | 937 | free_irq(irq, info); |
939 | release_regs: | 938 | release_regs: |
940 | iounmap(info->io); | 939 | iounmap(info->io); |
941 | release_mem: | 940 | release_mem: |
942 | release_resource(info->mem); | 941 | release_resource(info->mem); |
943 | kfree(info->mem); | 942 | kfree(info->mem); |
944 | dealloc_fb: | 943 | dealloc_fb: |
944 | platform_set_drvdata(pdev, NULL); | ||
945 | framebuffer_release(fbinfo); | 945 | framebuffer_release(fbinfo); |
946 | return ret; | 946 | return ret; |
947 | } | 947 | } |
@@ -949,8 +949,7 @@ dealloc_fb: | |||
949 | /* s3c2410fb_stop_lcd | 949 | /* s3c2410fb_stop_lcd |
950 | * | 950 | * |
951 | * shutdown the lcd controller | 951 | * shutdown the lcd controller |
952 | */ | 952 | */ |
953 | |||
954 | static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) | 953 | static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) |
955 | { | 954 | { |
956 | unsigned long flags; | 955 | unsigned long flags; |
@@ -968,28 +967,33 @@ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) | |||
968 | */ | 967 | */ |
969 | static int s3c2410fb_remove(struct platform_device *pdev) | 968 | static int s3c2410fb_remove(struct platform_device *pdev) |
970 | { | 969 | { |
971 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | 970 | struct fb_info *fbinfo = platform_get_drvdata(pdev); |
972 | struct s3c2410fb_info *info = fbinfo->par; | 971 | struct s3c2410fb_info *info = fbinfo->par; |
973 | int irq; | 972 | int irq; |
974 | 973 | ||
974 | unregister_framebuffer(fbinfo); | ||
975 | |||
975 | s3c2410fb_stop_lcd(info); | 976 | s3c2410fb_stop_lcd(info); |
976 | msleep(1); | 977 | msleep(1); |
977 | 978 | ||
978 | s3c2410fb_unmap_video_memory(info); | 979 | s3c2410fb_unmap_video_memory(fbinfo); |
979 | 980 | ||
980 | if (info->clk) { | 981 | if (info->clk) { |
981 | clk_disable(info->clk); | 982 | clk_disable(info->clk); |
982 | clk_put(info->clk); | 983 | clk_put(info->clk); |
983 | info->clk = NULL; | 984 | info->clk = NULL; |
984 | } | 985 | } |
985 | 986 | ||
986 | irq = platform_get_irq(pdev, 0); | 987 | irq = platform_get_irq(pdev, 0); |
987 | free_irq(irq,info); | 988 | free_irq(irq, info); |
989 | |||
990 | iounmap(info->io); | ||
988 | 991 | ||
989 | release_resource(info->mem); | 992 | release_resource(info->mem); |
990 | kfree(info->mem); | 993 | kfree(info->mem); |
991 | iounmap(info->io); | 994 | |
992 | unregister_framebuffer(fbinfo); | 995 | platform_set_drvdata(pdev, NULL); |
996 | framebuffer_release(fbinfo); | ||
993 | 997 | ||
994 | return 0; | 998 | return 0; |
995 | } | 999 | } |
@@ -997,7 +1001,6 @@ static int s3c2410fb_remove(struct platform_device *pdev) | |||
997 | #ifdef CONFIG_PM | 1001 | #ifdef CONFIG_PM |
998 | 1002 | ||
999 | /* suspend and resume support for the lcd controller */ | 1003 | /* suspend and resume support for the lcd controller */ |
1000 | |||
1001 | static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) | 1004 | static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) |
1002 | { | 1005 | { |
1003 | struct fb_info *fbinfo = platform_get_drvdata(dev); | 1006 | struct fb_info *fbinfo = platform_get_drvdata(dev); |
@@ -1044,7 +1047,7 @@ static struct platform_driver s3c2410fb_driver = { | |||
1044 | }, | 1047 | }, |
1045 | }; | 1048 | }; |
1046 | 1049 | ||
1047 | int __devinit s3c2410fb_init(void) | 1050 | int __init s3c2410fb_init(void) |
1048 | { | 1051 | { |
1049 | return platform_driver_register(&s3c2410fb_driver); | 1052 | return platform_driver_register(&s3c2410fb_driver); |
1050 | } | 1053 | } |
@@ -1054,10 +1057,10 @@ static void __exit s3c2410fb_cleanup(void) | |||
1054 | platform_driver_unregister(&s3c2410fb_driver); | 1057 | platform_driver_unregister(&s3c2410fb_driver); |
1055 | } | 1058 | } |
1056 | 1059 | ||
1057 | |||
1058 | module_init(s3c2410fb_init); | 1060 | module_init(s3c2410fb_init); |
1059 | module_exit(s3c2410fb_cleanup); | 1061 | module_exit(s3c2410fb_cleanup); |
1060 | 1062 | ||
1061 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, Ben Dooks <ben-linux@fluff.org>"); | 1063 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " |
1064 | "Ben Dooks <ben-linux@fluff.org>"); | ||
1062 | MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); | 1065 | MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); |
1063 | MODULE_LICENSE("GPL"); | 1066 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 17c7915b7acd..6ce5dc26c5f7 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h | |||
@@ -16,7 +16,7 @@ | |||
16 | * | 16 | * |
17 | * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> | 17 | * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> |
18 | * - Renamed from h1940fb.h to s3c2410fb.h | 18 | * - Renamed from h1940fb.h to s3c2410fb.h |
19 | * - Chenged h1940 to s3c2410 | 19 | * - Changed h1940 to s3c2410 |
20 | * | 20 | * |
21 | * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> | 21 | * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> |
22 | * - First version | 22 | * - First version |
@@ -26,25 +26,14 @@ | |||
26 | #define __S3C2410FB_H | 26 | #define __S3C2410FB_H |
27 | 27 | ||
28 | struct s3c2410fb_info { | 28 | struct s3c2410fb_info { |
29 | struct fb_info *fb; | ||
30 | struct device *dev; | 29 | struct device *dev; |
31 | struct clk *clk; | 30 | struct clk *clk; |
32 | 31 | ||
33 | struct resource *mem; | 32 | struct resource *mem; |
34 | void __iomem *io; | 33 | void __iomem *io; |
35 | 34 | ||
36 | struct s3c2410fb_mach_info *mach_info; | ||
37 | |||
38 | /* raw memory addresses */ | ||
39 | dma_addr_t map_dma; /* physical */ | ||
40 | u_char * map_cpu; /* virtual */ | ||
41 | u_int map_size; | ||
42 | |||
43 | struct s3c2410fb_hw regs; | 35 | struct s3c2410fb_hw regs; |
44 | 36 | ||
45 | /* addresses of pieces placed in raw buffer */ | ||
46 | u_char * screen_cpu; /* virtual address of buffer */ | ||
47 | dma_addr_t screen_dma; /* physical address of buffer */ | ||
48 | unsigned int palette_ready; | 37 | unsigned int palette_ready; |
49 | 38 | ||
50 | /* keep these registers in case we need to re-write palette */ | 39 | /* keep these registers in case we need to re-write palette */ |
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index d11735895a01..7d53bc23b9c7 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c | |||
@@ -400,11 +400,17 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
400 | { | 400 | { |
401 | struct s3fb_info *par = info->par; | 401 | struct s3fb_info *par = info->par; |
402 | int rv, mem, step; | 402 | int rv, mem, step; |
403 | u16 m, n, r; | ||
403 | 404 | ||
404 | /* Find appropriate format */ | 405 | /* Find appropriate format */ |
405 | rv = svga_match_format (s3fb_formats, var, NULL); | 406 | rv = svga_match_format (s3fb_formats, var, NULL); |
406 | if ((rv < 0) || ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))) | 407 | |
407 | { /* 24bpp on VIRGE VX, 32bpp on others */ | 408 | /* 32bpp mode is not supported on VIRGE VX, |
409 | 24bpp is not supported on others */ | ||
410 | if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)) | ||
411 | rv = -EINVAL; | ||
412 | |||
413 | if (rv < 0) { | ||
408 | printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); | 414 | printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); |
409 | return rv; | 415 | return rv; |
410 | } | 416 | } |
@@ -422,20 +428,26 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
422 | 428 | ||
423 | /* Check whether have enough memory */ | 429 | /* Check whether have enough memory */ |
424 | mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; | 430 | mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; |
425 | if (mem > info->screen_size) | 431 | if (mem > info->screen_size) { |
426 | { | ||
427 | printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", | 432 | printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", |
428 | info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); | 433 | info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); |
429 | return -EINVAL; | 434 | return -EINVAL; |
430 | } | 435 | } |
431 | 436 | ||
432 | rv = svga_check_timings (&s3_timing_regs, var, info->node); | 437 | rv = svga_check_timings (&s3_timing_regs, var, info->node); |
433 | if (rv < 0) | 438 | if (rv < 0) { |
434 | { | ||
435 | printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); | 439 | printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); |
436 | return rv; | 440 | return rv; |
437 | } | 441 | } |
438 | 442 | ||
443 | rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r, | ||
444 | info->node); | ||
445 | if (rv < 0) { | ||
446 | printk(KERN_ERR "fb%d: invalid pixclock value requested\n", | ||
447 | info->node); | ||
448 | return rv; | ||
449 | } | ||
450 | |||
439 | return 0; | 451 | return 0; |
440 | } | 452 | } |
441 | 453 | ||
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 5d2a4a4b731c..ab2b2110478b 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c | |||
@@ -178,7 +178,6 @@ | |||
178 | #include <asm/hardware.h> | 178 | #include <asm/hardware.h> |
179 | #include <asm/io.h> | 179 | #include <asm/io.h> |
180 | #include <asm/mach-types.h> | 180 | #include <asm/mach-types.h> |
181 | #include <asm/uaccess.h> | ||
182 | #include <asm/arch/assabet.h> | 181 | #include <asm/arch/assabet.h> |
183 | #include <asm/arch/shannon.h> | 182 | #include <asm/arch/shannon.h> |
184 | 183 | ||
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index b855f4a34afe..37b135d5d12e 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -57,7 +57,6 @@ | |||
57 | #include <asm/irq.h> | 57 | #include <asm/irq.h> |
58 | #include <asm/pgtable.h> | 58 | #include <asm/pgtable.h> |
59 | #include <asm/system.h> | 59 | #include <asm/system.h> |
60 | #include <asm/uaccess.h> | ||
61 | 60 | ||
62 | #ifdef CONFIG_MTRR | 61 | #ifdef CONFIG_MTRR |
63 | #include <asm/mtrr.h> | 62 | #include <asm/mtrr.h> |
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index e8ccace01252..bc7d23683735 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -58,7 +58,7 @@ | |||
58 | #include <linux/capability.h> | 58 | #include <linux/capability.h> |
59 | #include <linux/fs.h> | 59 | #include <linux/fs.h> |
60 | #include <linux/types.h> | 60 | #include <linux/types.h> |
61 | #include <asm/uaccess.h> | 61 | #include <linux/uaccess.h> |
62 | #include <asm/io.h> | 62 | #include <asm/io.h> |
63 | #ifdef CONFIG_MTRR | 63 | #ifdef CONFIG_MTRR |
64 | #include <asm/mtrr.h> | 64 | #include <asm/mtrr.h> |
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 64779e70408f..62321458f71a 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
@@ -780,7 +780,7 @@ static int __devinit xxxfb_probe(struct pci_dev *dev, | |||
780 | * | 780 | * |
781 | * NOTE: This field is currently unused. | 781 | * NOTE: This field is currently unused. |
782 | */ | 782 | */ |
783 | info->pixmap.scan_align = 32; | 783 | info->pixmap.access_align = 32; |
784 | /***************************** End optional stage ***************************/ | 784 | /***************************** End optional stage ***************************/ |
785 | 785 | ||
786 | /* | 786 | /* |
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index c86df126f93a..1be95a68d696 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
29 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/console.h> | ||
31 | 32 | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
@@ -62,6 +63,8 @@ struct sm501fb_info { | |||
62 | struct resource *regs_res; /* registers resource */ | 63 | struct resource *regs_res; /* registers resource */ |
63 | struct sm501_platdata_fb *pdata; /* our platform data */ | 64 | struct sm501_platdata_fb *pdata; /* our platform data */ |
64 | 65 | ||
66 | unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ | ||
67 | |||
65 | int irq; | 68 | int irq; |
66 | int swap_endian; /* set to swap rgb=>bgr */ | 69 | int swap_endian; /* set to swap rgb=>bgr */ |
67 | void __iomem *regs; /* remapped registers */ | 70 | void __iomem *regs; /* remapped registers */ |
@@ -774,6 +777,11 @@ static int sm501fb_set_par_pnl(struct fb_info *info) | |||
774 | writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); | 777 | writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); |
775 | sm501fb_sync_regs(fbi); | 778 | sm501fb_sync_regs(fbi); |
776 | 779 | ||
780 | /* ensure the panel interface is not tristated at this point */ | ||
781 | |||
782 | sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL, | ||
783 | 0, SM501_SYSCTRL_PANEL_TRISTATE); | ||
784 | |||
777 | /* power the panel up */ | 785 | /* power the panel up */ |
778 | sm501fb_panel_power(fbi, 1); | 786 | sm501fb_panel_power(fbi, 1); |
779 | return 0; | 787 | return 0; |
@@ -1687,19 +1695,25 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, | |||
1687 | goto err_nocursor; | 1695 | goto err_nocursor; |
1688 | } | 1696 | } |
1689 | 1697 | ||
1698 | dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb); | ||
1699 | dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor); | ||
1700 | |||
1690 | memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); | 1701 | memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); |
1691 | memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); | 1702 | memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); |
1692 | |||
1693 | /* blank the relevant interface to ensure unit power minimised */ | 1703 | /* blank the relevant interface to ensure unit power minimised */ |
1694 | (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); | 1704 | (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); |
1695 | 1705 | ||
1706 | acquire_console_sem(); | ||
1707 | fb_set_suspend(fbi, 1); | ||
1708 | release_console_sem(); | ||
1709 | |||
1696 | return 0; | 1710 | return 0; |
1697 | 1711 | ||
1698 | err_nocursor: | 1712 | err_nocursor: |
1699 | vfree(par->store_fb); | 1713 | vfree(par->store_fb); |
1714 | par->store_fb = NULL; | ||
1700 | 1715 | ||
1701 | return -ENOMEM; | 1716 | return -ENOMEM; |
1702 | |||
1703 | } | 1717 | } |
1704 | 1718 | ||
1705 | static void sm501fb_resume_fb(struct sm501fb_info *info, | 1719 | static void sm501fb_resume_fb(struct sm501fb_info *info, |
@@ -1717,8 +1731,20 @@ static void sm501fb_resume_fb(struct sm501fb_info *info, | |||
1717 | 1731 | ||
1718 | /* restore the data */ | 1732 | /* restore the data */ |
1719 | 1733 | ||
1720 | memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size); | 1734 | dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb); |
1721 | memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size); | 1735 | dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor); |
1736 | |||
1737 | if (par->store_fb) | ||
1738 | memcpy_toio(par->screen.k_addr, par->store_fb, | ||
1739 | par->screen.size); | ||
1740 | |||
1741 | if (par->store_cursor) | ||
1742 | memcpy_toio(par->cursor.k_addr, par->store_cursor, | ||
1743 | par->cursor.size); | ||
1744 | |||
1745 | acquire_console_sem(); | ||
1746 | fb_set_suspend(fbi, 0); | ||
1747 | release_console_sem(); | ||
1722 | 1748 | ||
1723 | vfree(par->store_fb); | 1749 | vfree(par->store_fb); |
1724 | vfree(par->store_cursor); | 1750 | vfree(par->store_cursor); |
@@ -1731,6 +1757,9 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) | |||
1731 | { | 1757 | { |
1732 | struct sm501fb_info *info = platform_get_drvdata(pdev); | 1758 | struct sm501fb_info *info = platform_get_drvdata(pdev); |
1733 | 1759 | ||
1760 | /* store crt control to resume with */ | ||
1761 | info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); | ||
1762 | |||
1734 | sm501fb_suspend_fb(info, HEAD_CRT); | 1763 | sm501fb_suspend_fb(info, HEAD_CRT); |
1735 | sm501fb_suspend_fb(info, HEAD_PANEL); | 1764 | sm501fb_suspend_fb(info, HEAD_PANEL); |
1736 | 1765 | ||
@@ -1740,12 +1769,24 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) | |||
1740 | return 0; | 1769 | return 0; |
1741 | } | 1770 | } |
1742 | 1771 | ||
1772 | #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \ | ||
1773 | SM501_DC_CRT_CONTROL_SEL) | ||
1774 | |||
1775 | |||
1743 | static int sm501fb_resume(struct platform_device *pdev) | 1776 | static int sm501fb_resume(struct platform_device *pdev) |
1744 | { | 1777 | { |
1745 | struct sm501fb_info *info = platform_get_drvdata(pdev); | 1778 | struct sm501fb_info *info = platform_get_drvdata(pdev); |
1779 | unsigned long crt_ctrl; | ||
1746 | 1780 | ||
1747 | sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1); | 1781 | sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1); |
1748 | 1782 | ||
1783 | /* restore the items we want to be saved for crt control */ | ||
1784 | |||
1785 | crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); | ||
1786 | crt_ctrl &= ~SM501_CRT_CTRL_SAVE; | ||
1787 | crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE; | ||
1788 | writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); | ||
1789 | |||
1749 | sm501fb_resume_fb(info, HEAD_CRT); | 1790 | sm501fb_resume_fb(info, HEAD_CRT); |
1750 | sm501fb_resume_fb(info, HEAD_PANEL); | 1791 | sm501fb_resume_fb(info, HEAD_PANEL); |
1751 | 1792 | ||
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 5eff28ce4f4d..97784f9c184d 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c | |||
@@ -88,7 +88,7 @@ | |||
88 | #include <linux/init.h> | 88 | #include <linux/init.h> |
89 | #include <linux/slab.h> | 89 | #include <linux/slab.h> |
90 | #include <asm/io.h> | 90 | #include <asm/io.h> |
91 | #include <asm/uaccess.h> | 91 | #include <linux/uaccess.h> |
92 | #include <video/sstfb.h> | 92 | #include <video/sstfb.h> |
93 | 93 | ||
94 | 94 | ||
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 25df928d37d8..9c7106701572 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c | |||
@@ -598,9 +598,11 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf | |||
598 | /* ------------------------------------------------------------------------- */ | 598 | /* ------------------------------------------------------------------------- */ |
599 | 599 | ||
600 | 600 | ||
601 | int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) | 601 | static inline int match_format(const struct svga_fb_format *frm, |
602 | struct fb_var_screeninfo *var) | ||
602 | { | 603 | { |
603 | int i = 0; | 604 | int i = 0; |
605 | int stored = -EINVAL; | ||
604 | 606 | ||
605 | while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) | 607 | while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) |
606 | { | 608 | { |
@@ -609,25 +611,38 @@ int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo | |||
609 | (var->green.length <= frm->green.length) && | 611 | (var->green.length <= frm->green.length) && |
610 | (var->blue.length <= frm->blue.length) && | 612 | (var->blue.length <= frm->blue.length) && |
611 | (var->transp.length <= frm->transp.length) && | 613 | (var->transp.length <= frm->transp.length) && |
612 | (var->nonstd == frm->nonstd)) { | 614 | (var->nonstd == frm->nonstd)) |
613 | var->bits_per_pixel = frm->bits_per_pixel; | ||
614 | var->red = frm->red; | ||
615 | var->green = frm->green; | ||
616 | var->blue = frm->blue; | ||
617 | var->transp = frm->transp; | ||
618 | var->nonstd = frm->nonstd; | ||
619 | if (fix != NULL) { | ||
620 | fix->type = frm->type; | ||
621 | fix->type_aux = frm->type_aux; | ||
622 | fix->visual = frm->visual; | ||
623 | fix->xpanstep = frm->xpanstep; | ||
624 | } | ||
625 | return i; | 615 | return i; |
626 | } | 616 | if (var->bits_per_pixel == frm->bits_per_pixel) |
617 | stored = i; | ||
627 | i++; | 618 | i++; |
628 | frm++; | 619 | frm++; |
629 | } | 620 | } |
630 | return -EINVAL; | 621 | return stored; |
622 | } | ||
623 | |||
624 | int svga_match_format(const struct svga_fb_format *frm, | ||
625 | struct fb_var_screeninfo *var, | ||
626 | struct fb_fix_screeninfo *fix) | ||
627 | { | ||
628 | int i = match_format(frm, var); | ||
629 | |||
630 | if (i >= 0) { | ||
631 | var->bits_per_pixel = frm[i].bits_per_pixel; | ||
632 | var->red = frm[i].red; | ||
633 | var->green = frm[i].green; | ||
634 | var->blue = frm[i].blue; | ||
635 | var->transp = frm[i].transp; | ||
636 | var->nonstd = frm[i].nonstd; | ||
637 | if (fix != NULL) { | ||
638 | fix->type = frm[i].type; | ||
639 | fix->type_aux = frm[i].type_aux; | ||
640 | fix->visual = frm[i].visual; | ||
641 | fix->xpanstep = frm[i].xpanstep; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | return i; | ||
631 | } | 646 | } |
632 | 647 | ||
633 | 648 | ||
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 689ce0270b81..057bdd593800 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c | |||
@@ -4,13 +4,13 @@ | |||
4 | * | 4 | * |
5 | * Author: Hannu Mallat <hmallat@cc.hut.fi> | 5 | * Author: Hannu Mallat <hmallat@cc.hut.fi> |
6 | * | 6 | * |
7 | * Copyright © 1999 Hannu Mallat | 7 | * Copyright © 1999 Hannu Mallat |
8 | * All rights reserved | 8 | * All rights reserved |
9 | * | 9 | * |
10 | * Created : Thu Sep 23 18:17:43 1999, hmallat | 10 | * Created : Thu Sep 23 18:17:43 1999, hmallat |
11 | * Last modified: Tue Nov 2 21:19:47 1999, hmallat | 11 | * Last modified: Tue Nov 2 21:19:47 1999, hmallat |
12 | * | 12 | * |
13 | * Lots of the information here comes from the Daryll Strauss' Banshee | 13 | * Lots of the information here comes from the Daryll Strauss' Banshee |
14 | * patches to the XF86 server, and the rest comes from the 3dfx | 14 | * patches to the XF86 server, and the rest comes from the 3dfx |
15 | * Banshee specification. I'm very much indebted to Daryll for his | 15 | * Banshee specification. I'm very much indebted to Daryll for his |
16 | * work on the X server. | 16 | * work on the X server. |
@@ -23,7 +23,7 @@ | |||
23 | * behave very differently from the Voodoo3/4/5. For anyone wanting to | 23 | * behave very differently from the Voodoo3/4/5. For anyone wanting to |
24 | * use frame buffer on the Voodoo1/2, see the sstfb driver (which is | 24 | * use frame buffer on the Voodoo1/2, see the sstfb driver (which is |
25 | * located at http://www.sourceforge.net/projects/sstfb). | 25 | * located at http://www.sourceforge.net/projects/sstfb). |
26 | * | 26 | * |
27 | * While I _am_ grateful to 3Dfx for releasing the specs for Banshee, | 27 | * While I _am_ grateful to 3Dfx for releasing the specs for Banshee, |
28 | * I do wish the next version is a bit more complete. Without the XF86 | 28 | * I do wish the next version is a bit more complete. Without the XF86 |
29 | * patches I couldn't have gotten even this far... for instance, the | 29 | * patches I couldn't have gotten even this far... for instance, the |
@@ -33,9 +33,8 @@ | |||
33 | * | 33 | * |
34 | * The structure of this driver comes pretty much from the Permedia | 34 | * The structure of this driver comes pretty much from the Permedia |
35 | * driver by Ilario Nardinocchi, which in turn is based on skeletonfb. | 35 | * driver by Ilario Nardinocchi, which in turn is based on skeletonfb. |
36 | * | 36 | * |
37 | * TODO: | 37 | * TODO: |
38 | * - support for 16/32 bpp needs fixing (funky bootup penguin) | ||
39 | * - multihead support (basically need to support an array of fb_infos) | 38 | * - multihead support (basically need to support an array of fb_infos) |
40 | * - support other architectures (PPC, Alpha); does the fact that the VGA | 39 | * - support other architectures (PPC, Alpha); does the fact that the VGA |
41 | * core can be accessed only thru I/O (not memory mapped) complicate | 40 | * core can be accessed only thru I/O (not memory mapped) complicate |
@@ -43,18 +42,18 @@ | |||
43 | * | 42 | * |
44 | * Version history: | 43 | * Version history: |
45 | * | 44 | * |
46 | * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons | 45 | * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons |
47 | * | 46 | * |
48 | * 0.1.3 (released 1999-11-02) added Attila's panning support, code | 47 | * 0.1.3 (released 1999-11-02) added Attila's panning support, code |
49 | * reorg, hwcursor address page size alignment | 48 | * reorg, hwcursor address page size alignment |
50 | * (for mmaping both frame buffer and regs), | 49 | * (for mmaping both frame buffer and regs), |
51 | * and my changes to get rid of hardcoded | 50 | * and my changes to get rid of hardcoded |
52 | * VGA i/o register locations (uses PCI | 51 | * VGA i/o register locations (uses PCI |
53 | * configuration info now) | 52 | * configuration info now) |
54 | * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and | 53 | * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and |
55 | * improvements | 54 | * improvements |
56 | * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga. | 55 | * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga. |
57 | * 0.1.0 (released 1999-10-06) initial version | 56 | * 0.1.0 (released 1999-10-06) initial version |
58 | * | 57 | * |
59 | */ | 58 | */ |
60 | 59 | ||
@@ -64,24 +63,32 @@ | |||
64 | #include <linux/string.h> | 63 | #include <linux/string.h> |
65 | #include <linux/mm.h> | 64 | #include <linux/mm.h> |
66 | #include <linux/slab.h> | 65 | #include <linux/slab.h> |
67 | #include <linux/delay.h> | ||
68 | #include <linux/interrupt.h> | ||
69 | #include <linux/fb.h> | 66 | #include <linux/fb.h> |
70 | #include <linux/init.h> | 67 | #include <linux/init.h> |
71 | #include <linux/pci.h> | 68 | #include <linux/pci.h> |
72 | #include <linux/nvram.h> | ||
73 | #include <asm/io.h> | 69 | #include <asm/io.h> |
74 | #include <linux/timer.h> | ||
75 | #include <linux/spinlock.h> | ||
76 | 70 | ||
77 | #include <video/tdfx.h> | 71 | #include <video/tdfx.h> |
78 | 72 | ||
79 | #undef TDFXFB_DEBUG | 73 | #define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b) |
80 | #ifdef TDFXFB_DEBUG | 74 | |
81 | #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b) | 75 | #ifdef CONFIG_MTRR |
76 | #include <asm/mtrr.h> | ||
82 | #else | 77 | #else |
83 | #define DPRINTK(a,b...) | 78 | /* duplicate asm/mtrr.h defines to work on archs without mtrr */ |
84 | #endif | 79 | #define MTRR_TYPE_WRCOMB 1 |
80 | |||
81 | static inline int mtrr_add(unsigned long base, unsigned long size, | ||
82 | unsigned int type, char increment) | ||
83 | { | ||
84 | return -ENODEV; | ||
85 | } | ||
86 | static inline int mtrr_del(int reg, unsigned long base, | ||
87 | unsigned long size) | ||
88 | { | ||
89 | return -ENODEV; | ||
90 | } | ||
91 | #endif | ||
85 | 92 | ||
86 | #define BANSHEE_MAX_PIXCLOCK 270000 | 93 | #define BANSHEE_MAX_PIXCLOCK 270000 |
87 | #define VOODOO3_MAX_PIXCLOCK 300000 | 94 | #define VOODOO3_MAX_PIXCLOCK 300000 |
@@ -90,9 +97,9 @@ | |||
90 | static struct fb_fix_screeninfo tdfx_fix __devinitdata = { | 97 | static struct fb_fix_screeninfo tdfx_fix __devinitdata = { |
91 | .id = "3Dfx", | 98 | .id = "3Dfx", |
92 | .type = FB_TYPE_PACKED_PIXELS, | 99 | .type = FB_TYPE_PACKED_PIXELS, |
93 | .visual = FB_VISUAL_PSEUDOCOLOR, | 100 | .visual = FB_VISUAL_PSEUDOCOLOR, |
94 | .ypanstep = 1, | 101 | .ypanstep = 1, |
95 | .ywrapstep = 1, | 102 | .ywrapstep = 1, |
96 | .accel = FB_ACCEL_3DFX_BANSHEE | 103 | .accel = FB_ACCEL_3DFX_BANSHEE |
97 | }; | 104 | }; |
98 | 105 | ||
@@ -102,7 +109,7 @@ static struct fb_var_screeninfo tdfx_var __devinitdata = { | |||
102 | .yres = 480, | 109 | .yres = 480, |
103 | .xres_virtual = 640, | 110 | .xres_virtual = 640, |
104 | .yres_virtual = 1024, | 111 | .yres_virtual = 1024, |
105 | .bits_per_pixel =8, | 112 | .bits_per_pixel = 8, |
106 | .red = {0, 8, 0}, | 113 | .red = {0, 8, 0}, |
107 | .blue = {0, 8, 0}, | 114 | .blue = {0, 8, 0}, |
108 | .green = {0, 8, 0}, | 115 | .green = {0, 8, 0}, |
@@ -142,103 +149,79 @@ static struct pci_device_id tdfxfb_id_table[] = { | |||
142 | 149 | ||
143 | static struct pci_driver tdfxfb_driver = { | 150 | static struct pci_driver tdfxfb_driver = { |
144 | .name = "tdfxfb", | 151 | .name = "tdfxfb", |
145 | .id_table = tdfxfb_id_table, | 152 | .id_table = tdfxfb_id_table, |
146 | .probe = tdfxfb_probe, | 153 | .probe = tdfxfb_probe, |
147 | .remove = __devexit_p(tdfxfb_remove), | 154 | .remove = __devexit_p(tdfxfb_remove), |
148 | }; | 155 | }; |
149 | 156 | ||
150 | MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); | 157 | MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); |
151 | 158 | ||
152 | /* | 159 | /* |
153 | * Frame buffer device API | 160 | * Driver data |
154 | */ | 161 | */ |
155 | static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); | 162 | static int nopan; |
156 | static int tdfxfb_set_par(struct fb_info *info); | 163 | static int nowrap = 1; /* not implemented (yet) */ |
157 | static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 164 | static int hwcursor = 1; |
158 | u_int transp, struct fb_info *info); | 165 | static char *mode_option __devinitdata; |
159 | static int tdfxfb_blank(int blank, struct fb_info *info); | 166 | /* mtrr option */ |
160 | static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); | 167 | static int nomtrr __devinitdata; |
161 | static int banshee_wait_idle(struct fb_info *info); | 168 | |
162 | #ifdef CONFIG_FB_3DFX_ACCEL | 169 | /* ------------------------------------------------------------------------- |
163 | static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); | 170 | * Hardware-specific funcions |
164 | static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); | ||
165 | static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image); | ||
166 | #endif /* CONFIG_FB_3DFX_ACCEL */ | ||
167 | |||
168 | static struct fb_ops tdfxfb_ops = { | ||
169 | .owner = THIS_MODULE, | ||
170 | .fb_check_var = tdfxfb_check_var, | ||
171 | .fb_set_par = tdfxfb_set_par, | ||
172 | .fb_setcolreg = tdfxfb_setcolreg, | ||
173 | .fb_blank = tdfxfb_blank, | ||
174 | .fb_pan_display = tdfxfb_pan_display, | ||
175 | .fb_sync = banshee_wait_idle, | ||
176 | #ifdef CONFIG_FB_3DFX_ACCEL | ||
177 | .fb_fillrect = tdfxfb_fillrect, | ||
178 | .fb_copyarea = tdfxfb_copyarea, | ||
179 | .fb_imageblit = tdfxfb_imageblit, | ||
180 | #else | ||
181 | .fb_fillrect = cfb_fillrect, | ||
182 | .fb_copyarea = cfb_copyarea, | ||
183 | .fb_imageblit = cfb_imageblit, | ||
184 | #endif | ||
185 | }; | ||
186 | |||
187 | /* | ||
188 | * do_xxx: Hardware-specific functions | ||
189 | */ | ||
190 | static u32 do_calc_pll(int freq, int *freq_out); | ||
191 | static void do_write_regs(struct fb_info *info, struct banshee_reg *reg); | ||
192 | static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short); | ||
193 | |||
194 | /* | ||
195 | * Driver data | ||
196 | */ | ||
197 | static int nopan = 0; | ||
198 | static int nowrap = 1; // not implemented (yet) | ||
199 | static char *mode_option __devinitdata = NULL; | ||
200 | |||
201 | /* ------------------------------------------------------------------------- | ||
202 | * Hardware-specific funcions | ||
203 | * ------------------------------------------------------------------------- */ | 171 | * ------------------------------------------------------------------------- */ |
204 | 172 | ||
205 | #ifdef VGA_REG_IO | 173 | static inline u8 vga_inb(struct tdfx_par *par, u32 reg) |
206 | static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); } | 174 | { |
207 | 175 | return inb(par->iobase + reg - 0x300); | |
208 | static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { outb(val, reg); } | ||
209 | #else | ||
210 | static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { | ||
211 | return inb(par->iobase + reg - 0x300); | ||
212 | } | 176 | } |
213 | static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { | 177 | |
214 | outb(val, par->iobase + reg - 0x300); | 178 | static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) |
179 | { | ||
180 | outb(val, par->iobase + reg - 0x300); | ||
215 | } | 181 | } |
216 | #endif | ||
217 | 182 | ||
218 | static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) { | 183 | static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) |
219 | vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val); | 184 | { |
185 | vga_outb(par, GRA_I, idx); | ||
186 | wmb(); | ||
187 | vga_outb(par, GRA_D, val); | ||
188 | wmb(); | ||
220 | } | 189 | } |
221 | 190 | ||
222 | static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) { | 191 | static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) |
223 | vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val); | 192 | { |
193 | vga_outb(par, SEQ_I, idx); | ||
194 | wmb(); | ||
195 | vga_outb(par, SEQ_D, val); | ||
196 | wmb(); | ||
224 | } | 197 | } |
225 | 198 | ||
226 | static inline u8 seq_inb(struct tdfx_par *par, u32 idx) { | 199 | static inline u8 seq_inb(struct tdfx_par *par, u32 idx) |
227 | vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D); | 200 | { |
201 | vga_outb(par, SEQ_I, idx); | ||
202 | mb(); | ||
203 | return vga_inb(par, SEQ_D); | ||
228 | } | 204 | } |
229 | 205 | ||
230 | static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) { | 206 | static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) |
231 | vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val); | 207 | { |
208 | vga_outb(par, CRT_I, idx); | ||
209 | wmb(); | ||
210 | vga_outb(par, CRT_D, val); | ||
211 | wmb(); | ||
232 | } | 212 | } |
233 | 213 | ||
234 | static inline u8 crt_inb(struct tdfx_par *par, u32 idx) { | 214 | static inline u8 crt_inb(struct tdfx_par *par, u32 idx) |
235 | vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D); | 215 | { |
216 | vga_outb(par, CRT_I, idx); | ||
217 | mb(); | ||
218 | return vga_inb(par, CRT_D); | ||
236 | } | 219 | } |
237 | 220 | ||
238 | static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) | 221 | static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) |
239 | { | 222 | { |
240 | unsigned char tmp; | 223 | unsigned char tmp; |
241 | 224 | ||
242 | tmp = vga_inb(par, IS1_R); | 225 | tmp = vga_inb(par, IS1_R); |
243 | vga_outb(par, ATT_IW, idx); | 226 | vga_outb(par, ATT_IW, idx); |
244 | vga_outb(par, ATT_IW, val); | 227 | vga_outb(par, ATT_IW, val); |
@@ -267,10 +250,11 @@ static inline void vga_enable_video(struct tdfx_par *par) | |||
267 | static inline void vga_enable_palette(struct tdfx_par *par) | 250 | static inline void vga_enable_palette(struct tdfx_par *par) |
268 | { | 251 | { |
269 | vga_inb(par, IS1_R); | 252 | vga_inb(par, IS1_R); |
253 | mb(); | ||
270 | vga_outb(par, ATT_IW, 0x20); | 254 | vga_outb(par, ATT_IW, 0x20); |
271 | } | 255 | } |
272 | 256 | ||
273 | static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) | 257 | static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) |
274 | { | 258 | { |
275 | return readl(par->regbase_virt + reg); | 259 | return readl(par->regbase_virt + reg); |
276 | } | 260 | } |
@@ -284,9 +268,10 @@ static inline void banshee_make_room(struct tdfx_par *par, int size) | |||
284 | { | 268 | { |
285 | /* Note: The Voodoo3's onboard FIFO has 32 slots. This loop | 269 | /* Note: The Voodoo3's onboard FIFO has 32 slots. This loop |
286 | * won't quit if you ask for more. */ | 270 | * won't quit if you ask for more. */ |
287 | while((tdfx_inl(par, STATUS) & 0x1f) < size-1); | 271 | while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1) |
272 | cpu_relax(); | ||
288 | } | 273 | } |
289 | 274 | ||
290 | static int banshee_wait_idle(struct fb_info *info) | 275 | static int banshee_wait_idle(struct fb_info *info) |
291 | { | 276 | { |
292 | struct tdfx_par *par = info->par; | 277 | struct tdfx_par *par = info->par; |
@@ -295,28 +280,31 @@ static int banshee_wait_idle(struct fb_info *info) | |||
295 | banshee_make_room(par, 1); | 280 | banshee_make_room(par, 1); |
296 | tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP); | 281 | tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP); |
297 | 282 | ||
298 | while(1) { | 283 | do { |
299 | i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1; | 284 | if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0) |
300 | if(i == 3) break; | 285 | i++; |
301 | } | 286 | } while (i < 3); |
287 | |||
302 | return 0; | 288 | return 0; |
303 | } | 289 | } |
304 | 290 | ||
305 | /* | 291 | /* |
306 | * Set the color of a palette entry in 8bpp mode | 292 | * Set the color of a palette entry in 8bpp mode |
307 | */ | 293 | */ |
308 | static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c) | 294 | static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c) |
309 | { | 295 | { |
310 | banshee_make_room(par, 2); | 296 | banshee_make_room(par, 2); |
311 | tdfx_outl(par, DACADDR, regno); | 297 | tdfx_outl(par, DACADDR, regno); |
298 | /* read after write makes it working */ | ||
299 | tdfx_inl(par, DACADDR); | ||
312 | tdfx_outl(par, DACDATA, c); | 300 | tdfx_outl(par, DACDATA, c); |
313 | } | 301 | } |
314 | 302 | ||
315 | static u32 do_calc_pll(int freq, int* freq_out) | 303 | static u32 do_calc_pll(int freq, int *freq_out) |
316 | { | 304 | { |
317 | int m, n, k, best_m, best_n, best_k, best_error; | 305 | int m, n, k, best_m, best_n, best_k, best_error; |
318 | int fref = 14318; | 306 | int fref = 14318; |
319 | 307 | ||
320 | best_error = freq; | 308 | best_error = freq; |
321 | best_n = best_m = best_k = 0; | 309 | best_n = best_m = best_k = 0; |
322 | 310 | ||
@@ -326,27 +314,28 @@ static u32 do_calc_pll(int freq, int* freq_out) | |||
326 | * Estimate value of n that produces target frequency | 314 | * Estimate value of n that produces target frequency |
327 | * with current m and k | 315 | * with current m and k |
328 | */ | 316 | */ |
329 | int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2; | 317 | int n_estimated = ((freq * (m + 2) << k) / fref) - 2; |
330 | 318 | ||
331 | /* Search neighborhood of estimated n */ | 319 | /* Search neighborhood of estimated n */ |
332 | for (n = max(0, n_estimated - 1); | 320 | for (n = max(0, n_estimated); |
333 | n <= min(255, n_estimated + 1); n++) { | 321 | n <= min(255, n_estimated + 1); |
322 | n++) { | ||
334 | /* | 323 | /* |
335 | * Calculate PLL freqency with current m, k and | 324 | * Calculate PLL freqency with current m, k and |
336 | * estimated n | 325 | * estimated n |
337 | */ | 326 | */ |
338 | int f = fref * (n + 2) / (m + 2) / (1 << k); | 327 | int f = (fref * (n + 2) / (m + 2)) >> k; |
339 | int error = abs (f - freq); | 328 | int error = abs(f - freq); |
340 | 329 | ||
341 | /* | 330 | /* |
342 | * If this is the closest we've come to the | 331 | * If this is the closest we've come to the |
343 | * target frequency then remember n, m and k | 332 | * target frequency then remember n, m and k |
344 | */ | 333 | */ |
345 | if (error < best_error) { | 334 | if (error < best_error) { |
346 | best_error = error; | 335 | best_error = error; |
347 | best_n = n; | 336 | best_n = n; |
348 | best_m = m; | 337 | best_m = m; |
349 | best_k = k; | 338 | best_k = k; |
350 | } | 339 | } |
351 | } | 340 | } |
352 | } | 341 | } |
@@ -355,12 +344,12 @@ static u32 do_calc_pll(int freq, int* freq_out) | |||
355 | n = best_n; | 344 | n = best_n; |
356 | m = best_m; | 345 | m = best_m; |
357 | k = best_k; | 346 | k = best_k; |
358 | *freq_out = fref*(n + 2)/(m + 2)/(1 << k); | 347 | *freq_out = (fref * (n + 2) / (m + 2)) >> k; |
359 | 348 | ||
360 | return (n << 8) | (m << 2) | k; | 349 | return (n << 8) | (m << 2) | k; |
361 | } | 350 | } |
362 | 351 | ||
363 | static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) | 352 | static void do_write_regs(struct fb_info *info, struct banshee_reg *reg) |
364 | { | 353 | { |
365 | struct tdfx_par *par = info->par; | 354 | struct tdfx_par *par = info->par; |
366 | int i; | 355 | int i; |
@@ -372,13 +361,13 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) | |||
372 | crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */ | 361 | crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */ |
373 | 362 | ||
374 | banshee_make_room(par, 3); | 363 | banshee_make_room(par, 3); |
375 | tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF); | 364 | tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF); |
376 | tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001); | 365 | tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001); |
377 | #if 0 | 366 | #if 0 |
378 | tdfx_outl(par, PLLCTRL1, reg->mempll); | 367 | tdfx_outl(par, PLLCTRL1, reg->mempll); |
379 | tdfx_outl(par, PLLCTRL2, reg->gfxpll); | 368 | tdfx_outl(par, PLLCTRL2, reg->gfxpll); |
380 | #endif | 369 | #endif |
381 | tdfx_outl(par, PLLCTRL0, reg->vidpll); | 370 | tdfx_outl(par, PLLCTRL0, reg->vidpll); |
382 | 371 | ||
383 | vga_outb(par, MISC_W, reg->misc[0x00] | 0x01); | 372 | vga_outb(par, MISC_W, reg->misc[0x00] | 0x01); |
384 | 373 | ||
@@ -400,72 +389,65 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) | |||
400 | vga_enable_palette(par); | 389 | vga_enable_palette(par); |
401 | vga_enable_video(par); | 390 | vga_enable_video(par); |
402 | 391 | ||
403 | banshee_make_room(par, 11); | 392 | banshee_make_room(par, 9); |
404 | tdfx_outl(par, VGAINIT0, reg->vgainit0); | 393 | tdfx_outl(par, VGAINIT0, reg->vgainit0); |
405 | tdfx_outl(par, DACMODE, reg->dacmode); | 394 | tdfx_outl(par, DACMODE, reg->dacmode); |
406 | tdfx_outl(par, VIDDESKSTRIDE, reg->stride); | 395 | tdfx_outl(par, VIDDESKSTRIDE, reg->stride); |
407 | tdfx_outl(par, HWCURPATADDR, 0); | 396 | tdfx_outl(par, HWCURPATADDR, reg->curspataddr); |
408 | 397 | ||
409 | tdfx_outl(par, VIDSCREENSIZE,reg->screensize); | 398 | tdfx_outl(par, VIDSCREENSIZE, reg->screensize); |
410 | tdfx_outl(par, VIDDESKSTART, reg->startaddr); | 399 | tdfx_outl(par, VIDDESKSTART, reg->startaddr); |
411 | tdfx_outl(par, VIDPROCCFG, reg->vidcfg); | 400 | tdfx_outl(par, VIDPROCCFG, reg->vidcfg); |
412 | tdfx_outl(par, VGAINIT1, reg->vgainit1); | 401 | tdfx_outl(par, VGAINIT1, reg->vgainit1); |
413 | tdfx_outl(par, MISCINIT0, reg->miscinit0); | 402 | tdfx_outl(par, MISCINIT0, reg->miscinit0); |
414 | 403 | ||
415 | banshee_make_room(par, 8); | 404 | banshee_make_room(par, 8); |
416 | tdfx_outl(par, SRCBASE, reg->srcbase); | 405 | tdfx_outl(par, SRCBASE, reg->startaddr); |
417 | tdfx_outl(par, DSTBASE, reg->dstbase); | 406 | tdfx_outl(par, DSTBASE, reg->startaddr); |
418 | tdfx_outl(par, COMMANDEXTRA_2D, 0); | 407 | tdfx_outl(par, COMMANDEXTRA_2D, 0); |
419 | tdfx_outl(par, CLIP0MIN, 0); | 408 | tdfx_outl(par, CLIP0MIN, 0); |
420 | tdfx_outl(par, CLIP0MAX, 0x0fff0fff); | 409 | tdfx_outl(par, CLIP0MAX, 0x0fff0fff); |
421 | tdfx_outl(par, CLIP1MIN, 0); | 410 | tdfx_outl(par, CLIP1MIN, 0); |
422 | tdfx_outl(par, CLIP1MAX, 0x0fff0fff); | 411 | tdfx_outl(par, CLIP1MAX, 0x0fff0fff); |
423 | tdfx_outl(par, SRCXY, 0); | 412 | tdfx_outl(par, SRCXY, 0); |
424 | 413 | ||
425 | banshee_wait_idle(info); | 414 | banshee_wait_idle(info); |
426 | } | 415 | } |
427 | 416 | ||
428 | static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) | 417 | static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) |
429 | { | 418 | { |
430 | u32 draminit0; | 419 | u32 draminit0 = tdfx_inl(par, DRAMINIT0); |
431 | u32 draminit1; | 420 | u32 draminit1 = tdfx_inl(par, DRAMINIT1); |
432 | u32 miscinit1; | 421 | u32 miscinit1; |
433 | 422 | int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4; | |
434 | int num_chips; | ||
435 | int chip_size; /* in MB */ | 423 | int chip_size; /* in MB */ |
436 | u32 lfbsize; | 424 | int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM; |
437 | int has_sgram; | ||
438 | 425 | ||
439 | draminit0 = tdfx_inl(par, DRAMINIT0); | ||
440 | draminit1 = tdfx_inl(par, DRAMINIT1); | ||
441 | |||
442 | num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4; | ||
443 | |||
444 | if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) { | 426 | if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) { |
445 | /* Banshee/Voodoo3 */ | 427 | /* Banshee/Voodoo3 */ |
446 | has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM; | 428 | chip_size = 2; |
447 | chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1) | 429 | if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE)) |
448 | : 2; | 430 | chip_size = 1; |
449 | } else { | 431 | } else { |
450 | /* Voodoo4/5 */ | 432 | /* Voodoo4/5 */ |
451 | has_sgram = 0; | 433 | has_sgram = 0; |
452 | chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT); | 434 | chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK; |
435 | chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT); | ||
453 | } | 436 | } |
454 | lfbsize = num_chips * chip_size * 1024 * 1024; | ||
455 | 437 | ||
456 | /* disable block writes for SDRAM */ | 438 | /* disable block writes for SDRAM */ |
457 | miscinit1 = tdfx_inl(par, MISCINIT1); | 439 | miscinit1 = tdfx_inl(par, MISCINIT1); |
458 | miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS; | 440 | miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS; |
459 | miscinit1 |= MISCINIT1_CLUT_INV; | 441 | miscinit1 |= MISCINIT1_CLUT_INV; |
460 | 442 | ||
461 | banshee_make_room(par, 1); | 443 | banshee_make_room(par, 1); |
462 | tdfx_outl(par, MISCINIT1, miscinit1); | 444 | tdfx_outl(par, MISCINIT1, miscinit1); |
463 | return lfbsize; | 445 | return num_chips * chip_size * 1024l * 1024; |
464 | } | 446 | } |
465 | 447 | ||
466 | /* ------------------------------------------------------------------------- */ | 448 | /* ------------------------------------------------------------------------- */ |
467 | 449 | ||
468 | static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) | 450 | static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
469 | { | 451 | { |
470 | struct tdfx_par *par = info->par; | 452 | struct tdfx_par *par = info->par; |
471 | u32 lpitch; | 453 | u32 lpitch; |
@@ -486,103 +468,113 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) | |||
486 | DPRINTK("xoffset not supported\n"); | 468 | DPRINTK("xoffset not supported\n"); |
487 | return -EINVAL; | 469 | return -EINVAL; |
488 | } | 470 | } |
471 | var->yoffset = 0; | ||
489 | 472 | ||
490 | /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ | 473 | /* |
491 | /* no direct information about device id now? use max_pixclock for this... */ | 474 | * Banshee doesn't support interlace, but Voodoo4/5 and probably |
475 | * Voodoo3 do. | ||
476 | * no direct information about device id now? | ||
477 | * use max_pixclock for this... | ||
478 | */ | ||
492 | if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) && | 479 | if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) && |
493 | (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { | 480 | (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { |
494 | DPRINTK("interlace not supported\n"); | 481 | DPRINTK("interlace not supported\n"); |
495 | return -EINVAL; | 482 | return -EINVAL; |
496 | } | 483 | } |
497 | 484 | ||
498 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ | 485 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ |
499 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); | 486 | lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); |
500 | 487 | ||
501 | if (var->xres < 320 || var->xres > 2048) { | 488 | if (var->xres < 320 || var->xres > 2048) { |
502 | DPRINTK("width not supported: %u\n", var->xres); | 489 | DPRINTK("width not supported: %u\n", var->xres); |
503 | return -EINVAL; | 490 | return -EINVAL; |
504 | } | 491 | } |
505 | 492 | ||
506 | if (var->yres < 200 || var->yres > 2048) { | 493 | if (var->yres < 200 || var->yres > 2048) { |
507 | DPRINTK("height not supported: %u\n", var->yres); | 494 | DPRINTK("height not supported: %u\n", var->yres); |
508 | return -EINVAL; | 495 | return -EINVAL; |
509 | } | 496 | } |
510 | 497 | ||
511 | if (lpitch * var->yres_virtual > info->fix.smem_len) { | 498 | if (lpitch * var->yres_virtual > info->fix.smem_len) { |
512 | var->yres_virtual = info->fix.smem_len/lpitch; | 499 | var->yres_virtual = info->fix.smem_len / lpitch; |
513 | if (var->yres_virtual < var->yres) { | 500 | if (var->yres_virtual < var->yres) { |
514 | DPRINTK("no memory for screen (%ux%ux%u)\n", | 501 | DPRINTK("no memory for screen (%ux%ux%u)\n", |
515 | var->xres, var->yres_virtual, var->bits_per_pixel); | 502 | var->xres, var->yres_virtual, |
503 | var->bits_per_pixel); | ||
516 | return -EINVAL; | 504 | return -EINVAL; |
517 | } | 505 | } |
518 | } | 506 | } |
519 | 507 | ||
520 | if (PICOS2KHZ(var->pixclock) > par->max_pixclock) { | 508 | if (PICOS2KHZ(var->pixclock) > par->max_pixclock) { |
521 | DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock)); | 509 | DPRINTK("pixclock too high (%ldKHz)\n", |
510 | PICOS2KHZ(var->pixclock)); | ||
522 | return -EINVAL; | 511 | return -EINVAL; |
523 | } | 512 | } |
524 | 513 | ||
525 | switch(var->bits_per_pixel) { | 514 | var->transp.offset = 0; |
526 | case 8: | 515 | var->transp.length = 0; |
527 | var->red.length = var->green.length = var->blue.length = 8; | 516 | switch (var->bits_per_pixel) { |
528 | break; | 517 | case 8: |
529 | case 16: | 518 | var->red.length = 8; |
530 | var->red.offset = 11; | 519 | var->red.offset = 0; |
531 | var->red.length = 5; | 520 | var->green = var->red; |
532 | var->green.offset = 5; | 521 | var->blue = var->red; |
533 | var->green.length = 6; | 522 | break; |
534 | var->blue.offset = 0; | 523 | case 16: |
535 | var->blue.length = 5; | 524 | var->red.offset = 11; |
536 | break; | 525 | var->red.length = 5; |
537 | case 24: | 526 | var->green.offset = 5; |
538 | var->red.offset=16; | 527 | var->green.length = 6; |
539 | var->green.offset=8; | 528 | var->blue.offset = 0; |
540 | var->blue.offset=0; | 529 | var->blue.length = 5; |
541 | var->red.length = var->green.length = var->blue.length = 8; | 530 | break; |
542 | case 32: | 531 | case 32: |
543 | var->red.offset = 16; | 532 | var->transp.offset = 24; |
544 | var->green.offset = 8; | 533 | var->transp.length = 8; |
545 | var->blue.offset = 0; | 534 | case 24: |
546 | var->red.length = var->green.length = var->blue.length = 8; | 535 | var->red.offset = 16; |
547 | break; | 536 | var->green.offset = 8; |
537 | var->blue.offset = 0; | ||
538 | var->red.length = var->green.length = var->blue.length = 8; | ||
539 | break; | ||
548 | } | 540 | } |
549 | var->height = var->width = -1; | 541 | var->width = -1; |
550 | 542 | var->height = -1; | |
543 | |||
551 | var->accel_flags = FB_ACCELF_TEXT; | 544 | var->accel_flags = FB_ACCELF_TEXT; |
552 | 545 | ||
553 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", var->xres, var->yres, var->bits_per_pixel); | 546 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", |
547 | var->xres, var->yres, var->bits_per_pixel); | ||
554 | return 0; | 548 | return 0; |
555 | } | 549 | } |
556 | 550 | ||
557 | static int tdfxfb_set_par(struct fb_info *info) | 551 | static int tdfxfb_set_par(struct fb_info *info) |
558 | { | 552 | { |
559 | struct tdfx_par *par = info->par; | 553 | struct tdfx_par *par = info->par; |
560 | u32 hdispend, hsyncsta, hsyncend, htotal; | 554 | u32 hdispend = info->var.xres; |
555 | u32 hsyncsta = hdispend + info->var.right_margin; | ||
556 | u32 hsyncend = hsyncsta + info->var.hsync_len; | ||
557 | u32 htotal = hsyncend + info->var.left_margin; | ||
561 | u32 hd, hs, he, ht, hbs, hbe; | 558 | u32 hd, hs, he, ht, hbs, hbe; |
562 | u32 vd, vs, ve, vt, vbs, vbe; | 559 | u32 vd, vs, ve, vt, vbs, vbe; |
563 | struct banshee_reg reg; | 560 | struct banshee_reg reg; |
564 | int fout, freq; | 561 | int fout, freq; |
565 | u32 wd, cpp; | 562 | u32 wd; |
566 | 563 | u32 cpp = (info->var.bits_per_pixel + 7) >> 3; | |
567 | par->baseline = 0; | 564 | |
568 | |||
569 | memset(®, 0, sizeof(reg)); | 565 | memset(®, 0, sizeof(reg)); |
570 | cpp = (info->var.bits_per_pixel + 7)/8; | 566 | |
571 | 567 | reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | | |
572 | reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); | 568 | VIDCFG_CURS_X11 | |
569 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | | ||
570 | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); | ||
573 | 571 | ||
574 | /* PLL settings */ | 572 | /* PLL settings */ |
575 | freq = PICOS2KHZ(info->var.pixclock); | 573 | freq = PICOS2KHZ(info->var.pixclock); |
576 | 574 | ||
577 | reg.dacmode = 0; | 575 | reg.vidcfg &= ~VIDCFG_2X; |
578 | reg.vidcfg &= ~VIDCFG_2X; | ||
579 | |||
580 | hdispend = info->var.xres; | ||
581 | hsyncsta = hdispend + info->var.right_margin; | ||
582 | hsyncend = hsyncsta + info->var.hsync_len; | ||
583 | htotal = hsyncend + info->var.left_margin; | ||
584 | 576 | ||
585 | if (freq > par->max_pixclock/2) { | 577 | if (freq > par->max_pixclock / 2) { |
586 | freq = freq > par->max_pixclock ? par->max_pixclock : freq; | 578 | freq = freq > par->max_pixclock ? par->max_pixclock : freq; |
587 | reg.dacmode |= DACMODE_2X; | 579 | reg.dacmode |= DACMODE_2X; |
588 | reg.vidcfg |= VIDCFG_2X; | 580 | reg.vidcfg |= VIDCFG_2X; |
@@ -591,8 +583,9 @@ static int tdfxfb_set_par(struct fb_info *info) | |||
591 | hsyncend >>= 1; | 583 | hsyncend >>= 1; |
592 | htotal >>= 1; | 584 | htotal >>= 1; |
593 | } | 585 | } |
594 | 586 | ||
595 | hd = wd = (hdispend >> 3) - 1; | 587 | wd = (hdispend >> 3) - 1; |
588 | hd = wd; | ||
596 | hs = (hsyncsta >> 3) - 1; | 589 | hs = (hsyncsta >> 3) - 1; |
597 | he = (hsyncend >> 3) - 1; | 590 | he = (hsyncend >> 3) - 1; |
598 | ht = (htotal >> 3) - 1; | 591 | ht = (htotal >> 3) - 1; |
@@ -600,28 +593,30 @@ static int tdfxfb_set_par(struct fb_info *info) | |||
600 | hbe = ht; | 593 | hbe = ht; |
601 | 594 | ||
602 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { | 595 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { |
603 | vbs = vd = (info->var.yres << 1) - 1; | 596 | vd = (info->var.yres << 1) - 1; |
604 | vs = vd + (info->var.lower_margin << 1); | 597 | vs = vd + (info->var.lower_margin << 1); |
605 | ve = vs + (info->var.vsync_len << 1); | 598 | ve = vs + (info->var.vsync_len << 1); |
606 | vbe = vt = ve + (info->var.upper_margin << 1) - 1; | 599 | vt = ve + (info->var.upper_margin << 1) - 1; |
600 | reg.screensize = info->var.xres | (info->var.yres << 13); | ||
601 | reg.vidcfg |= VIDCFG_HALF_MODE; | ||
602 | reg.crt[0x09] = 0x80; | ||
607 | } else { | 603 | } else { |
608 | vbs = vd = info->var.yres - 1; | 604 | vd = info->var.yres - 1; |
609 | vs = vd + info->var.lower_margin; | 605 | vs = vd + info->var.lower_margin; |
610 | ve = vs + info->var.vsync_len; | 606 | ve = vs + info->var.vsync_len; |
611 | vbe = vt = ve + info->var.upper_margin - 1; | 607 | vt = ve + info->var.upper_margin - 1; |
608 | reg.screensize = info->var.xres | (info->var.yres << 12); | ||
609 | reg.vidcfg &= ~VIDCFG_HALF_MODE; | ||
612 | } | 610 | } |
613 | 611 | vbs = vd; | |
612 | vbe = vt; | ||
613 | |||
614 | /* this is all pretty standard VGA register stuffing */ | 614 | /* this is all pretty standard VGA register stuffing */ |
615 | reg.misc[0x00] = 0x0f | | 615 | reg.misc[0x00] = 0x0f | |
616 | (info->var.xres < 400 ? 0xa0 : | 616 | (info->var.xres < 400 ? 0xa0 : |
617 | info->var.xres < 480 ? 0x60 : | 617 | info->var.xres < 480 ? 0x60 : |
618 | info->var.xres < 768 ? 0xe0 : 0x20); | 618 | info->var.xres < 768 ? 0xe0 : 0x20); |
619 | 619 | ||
620 | reg.gra[0x00] = 0x00; | ||
621 | reg.gra[0x01] = 0x00; | ||
622 | reg.gra[0x02] = 0x00; | ||
623 | reg.gra[0x03] = 0x00; | ||
624 | reg.gra[0x04] = 0x00; | ||
625 | reg.gra[0x05] = 0x40; | 620 | reg.gra[0x05] = 0x40; |
626 | reg.gra[0x06] = 0x05; | 621 | reg.gra[0x06] = 0x05; |
627 | reg.gra[0x07] = 0x0f; | 622 | reg.gra[0x07] = 0x0f; |
@@ -644,10 +639,7 @@ static int tdfxfb_set_par(struct fb_info *info) | |||
644 | reg.att[0x0e] = 0x0e; | 639 | reg.att[0x0e] = 0x0e; |
645 | reg.att[0x0f] = 0x0f; | 640 | reg.att[0x0f] = 0x0f; |
646 | reg.att[0x10] = 0x41; | 641 | reg.att[0x10] = 0x41; |
647 | reg.att[0x11] = 0x00; | ||
648 | reg.att[0x12] = 0x0f; | 642 | reg.att[0x12] = 0x0f; |
649 | reg.att[0x13] = 0x00; | ||
650 | reg.att[0x14] = 0x00; | ||
651 | 643 | ||
652 | reg.seq[0x00] = 0x03; | 644 | reg.seq[0x00] = 0x03; |
653 | reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */ | 645 | reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */ |
@@ -660,146 +652,133 @@ static int tdfxfb_set_par(struct fb_info *info) | |||
660 | reg.crt[0x02] = hbs; | 652 | reg.crt[0x02] = hbs; |
661 | reg.crt[0x03] = 0x80 | (hbe & 0x1f); | 653 | reg.crt[0x03] = 0x80 | (hbe & 0x1f); |
662 | reg.crt[0x04] = hs; | 654 | reg.crt[0x04] = hs; |
663 | reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); | 655 | reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); |
664 | reg.crt[0x06] = vt; | 656 | reg.crt[0x06] = vt; |
665 | reg.crt[0x07] = ((vs & 0x200) >> 2) | | 657 | reg.crt[0x07] = ((vs & 0x200) >> 2) | |
666 | ((vd & 0x200) >> 3) | | 658 | ((vd & 0x200) >> 3) | |
667 | ((vt & 0x200) >> 4) | 0x10 | | 659 | ((vt & 0x200) >> 4) | 0x10 | |
668 | ((vbs & 0x100) >> 5) | | 660 | ((vbs & 0x100) >> 5) | |
669 | ((vs & 0x100) >> 6) | | 661 | ((vs & 0x100) >> 6) | |
670 | ((vd & 0x100) >> 7) | | 662 | ((vd & 0x100) >> 7) | |
671 | ((vt & 0x100) >> 8); | 663 | ((vt & 0x100) >> 8); |
672 | reg.crt[0x08] = 0x00; | 664 | reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4); |
673 | reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); | ||
674 | reg.crt[0x0a] = 0x00; | ||
675 | reg.crt[0x0b] = 0x00; | ||
676 | reg.crt[0x0c] = 0x00; | ||
677 | reg.crt[0x0d] = 0x00; | ||
678 | reg.crt[0x0e] = 0x00; | ||
679 | reg.crt[0x0f] = 0x00; | ||
680 | reg.crt[0x10] = vs; | 665 | reg.crt[0x10] = vs; |
681 | reg.crt[0x11] = (ve & 0x0f) | 0x20; | 666 | reg.crt[0x11] = (ve & 0x0f) | 0x20; |
682 | reg.crt[0x12] = vd; | 667 | reg.crt[0x12] = vd; |
683 | reg.crt[0x13] = wd; | 668 | reg.crt[0x13] = wd; |
684 | reg.crt[0x14] = 0x00; | ||
685 | reg.crt[0x15] = vbs; | 669 | reg.crt[0x15] = vbs; |
686 | reg.crt[0x16] = vbe + 1; | 670 | reg.crt[0x16] = vbe + 1; |
687 | reg.crt[0x17] = 0xc3; | 671 | reg.crt[0x17] = 0xc3; |
688 | reg.crt[0x18] = 0xff; | 672 | reg.crt[0x18] = 0xff; |
689 | 673 | ||
690 | /* Banshee's nonvga stuff */ | 674 | /* Banshee's nonvga stuff */ |
691 | reg.ext[0x00] = (((ht & 0x100) >> 8) | | 675 | reg.ext[0x00] = (((ht & 0x100) >> 8) | |
692 | ((hd & 0x100) >> 6) | | 676 | ((hd & 0x100) >> 6) | |
693 | ((hbs & 0x100) >> 4) | | 677 | ((hbs & 0x100) >> 4) | |
694 | ((hbe & 0x40) >> 1) | | 678 | ((hbe & 0x40) >> 1) | |
695 | ((hs & 0x100) >> 2) | | 679 | ((hs & 0x100) >> 2) | |
696 | ((he & 0x20) << 2)); | 680 | ((he & 0x20) << 2)); |
697 | reg.ext[0x01] = (((vt & 0x400) >> 10) | | 681 | reg.ext[0x01] = (((vt & 0x400) >> 10) | |
698 | ((vd & 0x400) >> 8) | | 682 | ((vd & 0x400) >> 8) | |
699 | ((vbs & 0x400) >> 6) | | 683 | ((vbs & 0x400) >> 6) | |
700 | ((vbe & 0x400) >> 4)); | 684 | ((vbe & 0x400) >> 4)); |
701 | 685 | ||
702 | reg.vgainit0 = VGAINIT0_8BIT_DAC | | 686 | reg.vgainit0 = VGAINIT0_8BIT_DAC | |
703 | VGAINIT0_EXT_ENABLE | | 687 | VGAINIT0_EXT_ENABLE | |
704 | VGAINIT0_WAKEUP_3C3 | | 688 | VGAINIT0_WAKEUP_3C3 | |
705 | VGAINIT0_ALT_READBACK | | 689 | VGAINIT0_ALT_READBACK | |
706 | VGAINIT0_EXTSHIFTOUT; | 690 | VGAINIT0_EXTSHIFTOUT; |
707 | reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; | 691 | reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; |
708 | 692 | ||
693 | if (hwcursor) | ||
694 | reg.curspataddr = info->fix.smem_len; | ||
695 | |||
709 | reg.cursloc = 0; | 696 | reg.cursloc = 0; |
710 | 697 | ||
711 | reg.cursc0 = 0; | 698 | reg.cursc0 = 0; |
712 | reg.cursc1 = 0xffffff; | 699 | reg.cursc1 = 0xffffff; |
713 | |||
714 | reg.stride = info->var.xres * cpp; | ||
715 | reg.startaddr = par->baseline * reg.stride; | ||
716 | reg.srcbase = reg.startaddr; | ||
717 | reg.dstbase = reg.startaddr; | ||
718 | 700 | ||
719 | /* PLL settings */ | 701 | reg.stride = info->var.xres * cpp; |
720 | freq = PICOS2KHZ(info->var.pixclock); | 702 | reg.startaddr = info->var.yoffset * reg.stride |
703 | + info->var.xoffset * cpp; | ||
721 | 704 | ||
722 | reg.dacmode &= ~DACMODE_2X; | ||
723 | reg.vidcfg &= ~VIDCFG_2X; | ||
724 | if (freq > par->max_pixclock/2) { | ||
725 | freq = freq > par->max_pixclock ? par->max_pixclock : freq; | ||
726 | reg.dacmode |= DACMODE_2X; | ||
727 | reg.vidcfg |= VIDCFG_2X; | ||
728 | } | ||
729 | reg.vidpll = do_calc_pll(freq, &fout); | 705 | reg.vidpll = do_calc_pll(freq, &fout); |
730 | #if 0 | 706 | #if 0 |
731 | reg.mempll = do_calc_pll(..., &fout); | 707 | reg.mempll = do_calc_pll(..., &fout); |
732 | reg.gfxpll = do_calc_pll(..., &fout); | 708 | reg.gfxpll = do_calc_pll(..., &fout); |
733 | #endif | 709 | #endif |
734 | 710 | ||
735 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { | ||
736 | reg.screensize = info->var.xres | (info->var.yres << 13); | ||
737 | reg.vidcfg |= VIDCFG_HALF_MODE; | ||
738 | reg.crt[0x09] |= 0x80; | ||
739 | } else { | ||
740 | reg.screensize = info->var.xres | (info->var.yres << 12); | ||
741 | reg.vidcfg &= ~VIDCFG_HALF_MODE; | ||
742 | } | ||
743 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) | 711 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) |
744 | reg.vidcfg |= VIDCFG_INTERLACE; | 712 | reg.vidcfg |= VIDCFG_INTERLACE; |
745 | reg.miscinit0 = tdfx_inl(par, MISCINIT0); | 713 | reg.miscinit0 = tdfx_inl(par, MISCINIT0); |
746 | 714 | ||
747 | #if defined(__BIG_ENDIAN) | 715 | #if defined(__BIG_ENDIAN) |
748 | switch (info->var.bits_per_pixel) { | 716 | switch (info->var.bits_per_pixel) { |
749 | case 8: | 717 | case 8: |
750 | case 24: | 718 | case 24: |
751 | reg.miscinit0 &= ~(1 << 30); | 719 | reg.miscinit0 &= ~(1 << 30); |
752 | reg.miscinit0 &= ~(1 << 31); | 720 | reg.miscinit0 &= ~(1 << 31); |
753 | break; | 721 | break; |
754 | case 16: | 722 | case 16: |
755 | reg.miscinit0 |= (1 << 30); | 723 | reg.miscinit0 |= (1 << 30); |
756 | reg.miscinit0 |= (1 << 31); | 724 | reg.miscinit0 |= (1 << 31); |
757 | break; | 725 | break; |
758 | case 32: | 726 | case 32: |
759 | reg.miscinit0 |= (1 << 30); | 727 | reg.miscinit0 |= (1 << 30); |
760 | reg.miscinit0 &= ~(1 << 31); | 728 | reg.miscinit0 &= ~(1 << 31); |
761 | break; | 729 | break; |
762 | } | 730 | } |
763 | #endif | 731 | #endif |
764 | do_write_regs(info, ®); | 732 | do_write_regs(info, ®); |
765 | 733 | ||
766 | /* Now change fb_fix_screeninfo according to changes in par */ | 734 | /* Now change fb_fix_screeninfo according to changes in par */ |
767 | info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3); | 735 | info->fix.line_length = reg.stride; |
768 | info->fix.visual = (info->var.bits_per_pixel == 8) | 736 | info->fix.visual = (info->var.bits_per_pixel == 8) |
769 | ? FB_VISUAL_PSEUDOCOLOR | 737 | ? FB_VISUAL_PSEUDOCOLOR |
770 | : FB_VISUAL_TRUECOLOR; | 738 | : FB_VISUAL_TRUECOLOR; |
771 | DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); | 739 | DPRINTK("Graphics mode is now set at %dx%d depth %d\n", |
772 | return 0; | 740 | info->var.xres, info->var.yres, info->var.bits_per_pixel); |
741 | return 0; | ||
773 | } | 742 | } |
774 | 743 | ||
775 | /* A handy macro shamelessly pinched from matroxfb */ | 744 | /* A handy macro shamelessly pinched from matroxfb */ |
776 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 745 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) |
777 | 746 | ||
778 | static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | 747 | static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
779 | unsigned blue,unsigned transp,struct fb_info *info) | 748 | unsigned blue, unsigned transp, |
749 | struct fb_info *info) | ||
780 | { | 750 | { |
781 | struct tdfx_par *par = info->par; | 751 | struct tdfx_par *par = info->par; |
782 | u32 rgbcol; | 752 | u32 rgbcol; |
783 | 753 | ||
784 | if (regno >= info->cmap.len || regno > 255) return 1; | 754 | if (regno >= info->cmap.len || regno > 255) |
785 | 755 | return 1; | |
756 | |||
757 | /* grayscale works only partially under directcolor */ | ||
758 | if (info->var.grayscale) { | ||
759 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
760 | blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
761 | green = blue; | ||
762 | red = blue; | ||
763 | } | ||
764 | |||
786 | switch (info->fix.visual) { | 765 | switch (info->fix.visual) { |
787 | case FB_VISUAL_PSEUDOCOLOR: | 766 | case FB_VISUAL_PSEUDOCOLOR: |
788 | rgbcol =(((u32)red & 0xff00) << 8) | | 767 | rgbcol = (((u32)red & 0xff00) << 8) | |
789 | (((u32)green & 0xff00) << 0) | | 768 | (((u32)green & 0xff00) << 0) | |
790 | (((u32)blue & 0xff00) >> 8); | 769 | (((u32)blue & 0xff00) >> 8); |
791 | do_setpalentry(par, regno, rgbcol); | 770 | do_setpalentry(par, regno, rgbcol); |
792 | break; | 771 | break; |
793 | /* Truecolor has no hardware color palettes. */ | 772 | /* Truecolor has no hardware color palettes. */ |
794 | case FB_VISUAL_TRUECOLOR: | 773 | case FB_VISUAL_TRUECOLOR: |
795 | if (regno < 16) { | 774 | if (regno < 16) { |
796 | rgbcol = (CNVT_TOHW( red, info->var.red.length) << | 775 | rgbcol = (CNVT_TOHW(red, info->var.red.length) << |
797 | info->var.red.offset) | | 776 | info->var.red.offset) | |
798 | (CNVT_TOHW( green, info->var.green.length) << | 777 | (CNVT_TOHW(green, info->var.green.length) << |
799 | info->var.green.offset) | | 778 | info->var.green.offset) | |
800 | (CNVT_TOHW( blue, info->var.blue.length) << | 779 | (CNVT_TOHW(blue, info->var.blue.length) << |
801 | info->var.blue.offset) | | 780 | info->var.blue.offset) | |
802 | (CNVT_TOHW( transp, info->var.transp.length) << | 781 | (CNVT_TOHW(transp, info->var.transp.length) << |
803 | info->var.transp.offset); | 782 | info->var.transp.offset); |
804 | par->palette[regno] = rgbcol; | 783 | par->palette[regno] = rgbcol; |
805 | } | 784 | } |
@@ -815,287 +794,325 @@ static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
815 | 794 | ||
816 | /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ | 795 | /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ |
817 | static int tdfxfb_blank(int blank, struct fb_info *info) | 796 | static int tdfxfb_blank(int blank, struct fb_info *info) |
818 | { | 797 | { |
819 | struct tdfx_par *par = info->par; | 798 | struct tdfx_par *par = info->par; |
820 | u32 dacmode, state = 0, vgablank = 0; | 799 | int vgablank = 1; |
800 | u32 dacmode = tdfx_inl(par, DACMODE); | ||
821 | 801 | ||
822 | dacmode = tdfx_inl(par, DACMODE); | 802 | dacmode &= ~(BIT(1) | BIT(3)); |
823 | 803 | ||
824 | switch (blank) { | 804 | switch (blank) { |
825 | case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */ | 805 | case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */ |
826 | state = 0; | 806 | vgablank = 0; |
827 | vgablank = 0; | 807 | break; |
828 | break; | 808 | case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */ |
829 | case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */ | 809 | break; |
830 | state = 0; | 810 | case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */ |
831 | vgablank = 1; | 811 | dacmode |= BIT(3); |
832 | break; | 812 | break; |
833 | case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */ | 813 | case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */ |
834 | state = BIT(3); | 814 | dacmode |= BIT(1); |
835 | vgablank = 1; | 815 | break; |
836 | break; | 816 | case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */ |
837 | case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */ | 817 | dacmode |= BIT(1) | BIT(3); |
838 | state = BIT(1); | 818 | break; |
839 | vgablank = 1; | ||
840 | break; | ||
841 | case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */ | ||
842 | state = BIT(1) | BIT(3); | ||
843 | vgablank = 1; | ||
844 | break; | ||
845 | } | 819 | } |
846 | 820 | ||
847 | dacmode &= ~(BIT(1) | BIT(3)); | 821 | banshee_make_room(par, 1); |
848 | dacmode |= state; | ||
849 | banshee_make_room(par, 1); | ||
850 | tdfx_outl(par, DACMODE, dacmode); | 822 | tdfx_outl(par, DACMODE, dacmode); |
851 | if (vgablank) | 823 | if (vgablank) |
852 | vga_disable_video(par); | 824 | vga_disable_video(par); |
853 | else | 825 | else |
854 | vga_enable_video(par); | 826 | vga_enable_video(par); |
855 | return 0; | 827 | return 0; |
856 | } | 828 | } |
857 | 829 | ||
858 | /* | 830 | /* |
859 | * Set the starting position of the visible screen to var->yoffset | 831 | * Set the starting position of the visible screen to var->yoffset |
860 | */ | 832 | */ |
861 | static int tdfxfb_pan_display(struct fb_var_screeninfo *var, | 833 | static int tdfxfb_pan_display(struct fb_var_screeninfo *var, |
862 | struct fb_info *info) | 834 | struct fb_info *info) |
863 | { | 835 | { |
864 | struct tdfx_par *par = info->par; | 836 | struct tdfx_par *par = info->par; |
865 | u32 addr; | 837 | u32 addr = var->yoffset * info->fix.line_length; |
866 | 838 | ||
867 | if (nopan || var->xoffset || (var->yoffset > var->yres_virtual)) | 839 | if (nopan || var->xoffset || (var->yoffset > var->yres_virtual)) |
868 | return -EINVAL; | 840 | return -EINVAL; |
869 | if ((var->yoffset + var->yres > var->yres_virtual && nowrap)) | 841 | if ((var->yoffset + var->yres > var->yres_virtual && nowrap)) |
870 | return -EINVAL; | 842 | return -EINVAL; |
871 | 843 | ||
872 | addr = var->yoffset * info->fix.line_length; | ||
873 | banshee_make_room(par, 1); | 844 | banshee_make_room(par, 1); |
874 | tdfx_outl(par, VIDDESKSTART, addr); | 845 | tdfx_outl(par, VIDDESKSTART, addr); |
875 | 846 | ||
876 | info->var.xoffset = var->xoffset; | 847 | info->var.xoffset = var->xoffset; |
877 | info->var.yoffset = var->yoffset; | 848 | info->var.yoffset = var->yoffset; |
878 | return 0; | 849 | return 0; |
879 | } | 850 | } |
880 | 851 | ||
881 | #ifdef CONFIG_FB_3DFX_ACCEL | 852 | #ifdef CONFIG_FB_3DFX_ACCEL |
882 | /* | 853 | /* |
883 | * FillRect 2D command (solidfill or invert (via ROP_XOR)) | 854 | * FillRect 2D command (solidfill or invert (via ROP_XOR)) |
884 | */ | 855 | */ |
885 | static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | 856 | static void tdfxfb_fillrect(struct fb_info *info, |
857 | const struct fb_fillrect *rect) | ||
886 | { | 858 | { |
887 | struct tdfx_par *par = info->par; | 859 | struct tdfx_par *par = info->par; |
888 | u32 bpp = info->var.bits_per_pixel; | 860 | u32 bpp = info->var.bits_per_pixel; |
889 | u32 stride = info->fix.line_length; | 861 | u32 stride = info->fix.line_length; |
890 | u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); | 862 | u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
891 | int tdfx_rop; | 863 | int tdfx_rop; |
892 | 864 | u32 dx = rect->dx; | |
893 | if (rect->rop == ROP_COPY) | 865 | u32 dy = rect->dy; |
866 | u32 dstbase = 0; | ||
867 | |||
868 | if (rect->rop == ROP_COPY) | ||
894 | tdfx_rop = TDFX_ROP_COPY; | 869 | tdfx_rop = TDFX_ROP_COPY; |
895 | else | 870 | else |
896 | tdfx_rop = TDFX_ROP_XOR; | 871 | tdfx_rop = TDFX_ROP_XOR; |
897 | 872 | ||
898 | banshee_make_room(par, 5); | 873 | /* asume always rect->height < 4096 */ |
899 | tdfx_outl(par, DSTFORMAT, fmt); | 874 | if (dy + rect->height > 4095) { |
875 | dstbase = stride * dy; | ||
876 | dy = 0; | ||
877 | } | ||
878 | /* asume always rect->width < 4096 */ | ||
879 | if (dx + rect->width > 4095) { | ||
880 | dstbase += dx * bpp >> 3; | ||
881 | dx = 0; | ||
882 | } | ||
883 | banshee_make_room(par, 6); | ||
884 | tdfx_outl(par, DSTFORMAT, fmt); | ||
900 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { | 885 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { |
901 | tdfx_outl(par, COLORFORE, rect->color); | 886 | tdfx_outl(par, COLORFORE, rect->color); |
902 | } else { /* FB_VISUAL_TRUECOLOR */ | 887 | } else { /* FB_VISUAL_TRUECOLOR */ |
903 | tdfx_outl(par, COLORFORE, par->palette[rect->color]); | 888 | tdfx_outl(par, COLORFORE, par->palette[rect->color]); |
904 | } | 889 | } |
905 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); | 890 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); |
906 | tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); | 891 | tdfx_outl(par, DSTBASE, dstbase); |
907 | tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); | 892 | tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); |
893 | tdfx_outl(par, LAUNCH_2D, dx | (dy << 16)); | ||
908 | } | 894 | } |
909 | 895 | ||
910 | /* | 896 | /* |
911 | * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) | 897 | * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) |
912 | */ | 898 | */ |
913 | static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | 899 | static void tdfxfb_copyarea(struct fb_info *info, |
900 | const struct fb_copyarea *area) | ||
914 | { | 901 | { |
915 | struct tdfx_par *par = info->par; | 902 | struct tdfx_par *par = info->par; |
916 | u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; | 903 | u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; |
917 | u32 bpp = info->var.bits_per_pixel; | 904 | u32 bpp = info->var.bits_per_pixel; |
918 | u32 stride = info->fix.line_length; | 905 | u32 stride = info->fix.line_length; |
919 | u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); | 906 | u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); |
920 | u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); | 907 | u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
921 | 908 | u32 dstbase = 0; | |
909 | u32 srcbase = 0; | ||
910 | |||
911 | /* asume always area->height < 4096 */ | ||
912 | if (sy + area->height > 4095) { | ||
913 | srcbase = stride * sy; | ||
914 | sy = 0; | ||
915 | } | ||
916 | /* asume always area->width < 4096 */ | ||
917 | if (sx + area->width > 4095) { | ||
918 | srcbase += sx * bpp >> 3; | ||
919 | sx = 0; | ||
920 | } | ||
921 | /* asume always area->height < 4096 */ | ||
922 | if (dy + area->height > 4095) { | ||
923 | dstbase = stride * dy; | ||
924 | dy = 0; | ||
925 | } | ||
926 | /* asume always area->width < 4096 */ | ||
927 | if (dx + area->width > 4095) { | ||
928 | dstbase += dx * bpp >> 3; | ||
929 | dx = 0; | ||
930 | } | ||
931 | |||
922 | if (area->sx <= area->dx) { | 932 | if (area->sx <= area->dx) { |
923 | //-X | 933 | /* -X */ |
924 | blitcmd |= BIT(14); | 934 | blitcmd |= BIT(14); |
925 | sx += area->width - 1; | 935 | sx += area->width - 1; |
926 | dx += area->width - 1; | 936 | dx += area->width - 1; |
927 | } | 937 | } |
928 | if (area->sy <= area->dy) { | 938 | if (area->sy <= area->dy) { |
929 | //-Y | 939 | /* -Y */ |
930 | blitcmd |= BIT(15); | 940 | blitcmd |= BIT(15); |
931 | sy += area->height - 1; | 941 | sy += area->height - 1; |
932 | dy += area->height - 1; | 942 | dy += area->height - 1; |
933 | } | 943 | } |
934 | |||
935 | banshee_make_room(par, 6); | ||
936 | 944 | ||
937 | tdfx_outl(par, SRCFORMAT, fmt); | 945 | banshee_make_room(par, 8); |
938 | tdfx_outl(par, DSTFORMAT, fmt); | 946 | |
939 | tdfx_outl(par, COMMAND_2D, blitcmd); | 947 | tdfx_outl(par, SRCFORMAT, fmt); |
940 | tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); | 948 | tdfx_outl(par, DSTFORMAT, fmt); |
941 | tdfx_outl(par, DSTXY, dx | (dy << 16)); | 949 | tdfx_outl(par, COMMAND_2D, blitcmd); |
942 | tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); | 950 | tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); |
951 | tdfx_outl(par, DSTXY, dx | (dy << 16)); | ||
952 | tdfx_outl(par, SRCBASE, srcbase); | ||
953 | tdfx_outl(par, DSTBASE, dstbase); | ||
954 | tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); | ||
943 | } | 955 | } |
944 | 956 | ||
945 | static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) | 957 | static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) |
946 | { | 958 | { |
947 | struct tdfx_par *par = info->par; | 959 | struct tdfx_par *par = info->par; |
948 | int size = image->height * ((image->width * image->depth + 7)>>3); | 960 | int size = image->height * ((image->width * image->depth + 7) >> 3); |
949 | int fifo_free; | 961 | int fifo_free; |
950 | int i, stride = info->fix.line_length; | 962 | int i, stride = info->fix.line_length; |
951 | u32 bpp = info->var.bits_per_pixel; | 963 | u32 bpp = info->var.bits_per_pixel; |
952 | u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); | 964 | u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
953 | u8 *chardata = (u8 *) image->data; | 965 | u8 *chardata = (u8 *) image->data; |
954 | u32 srcfmt; | 966 | u32 srcfmt; |
967 | u32 dx = image->dx; | ||
968 | u32 dy = image->dy; | ||
969 | u32 dstbase = 0; | ||
955 | 970 | ||
956 | if (image->depth != 1) { | 971 | if (image->depth != 1) { |
957 | //banshee_make_room(par, 6 + ((size + 3) >> 2)); | 972 | #ifdef BROKEN_CODE |
958 | //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; | 973 | banshee_make_room(par, 6 + ((size + 3) >> 2)); |
974 | srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) | | ||
975 | 0x400000; | ||
976 | #else | ||
959 | cfb_imageblit(info, image); | 977 | cfb_imageblit(info, image); |
978 | #endif | ||
960 | return; | 979 | return; |
961 | } else { | 980 | } |
962 | banshee_make_room(par, 8); | 981 | banshee_make_room(par, 9); |
963 | switch (info->fix.visual) { | 982 | switch (info->fix.visual) { |
964 | case FB_VISUAL_PSEUDOCOLOR: | 983 | case FB_VISUAL_PSEUDOCOLOR: |
965 | tdfx_outl(par, COLORFORE, image->fg_color); | 984 | tdfx_outl(par, COLORFORE, image->fg_color); |
966 | tdfx_outl(par, COLORBACK, image->bg_color); | 985 | tdfx_outl(par, COLORBACK, image->bg_color); |
967 | break; | 986 | break; |
968 | case FB_VISUAL_TRUECOLOR: | 987 | case FB_VISUAL_TRUECOLOR: |
969 | default: | 988 | default: |
970 | tdfx_outl(par, COLORFORE, | 989 | tdfx_outl(par, COLORFORE, |
971 | par->palette[image->fg_color]); | 990 | par->palette[image->fg_color]); |
972 | tdfx_outl(par, COLORBACK, | 991 | tdfx_outl(par, COLORBACK, |
973 | par->palette[image->bg_color]); | 992 | par->palette[image->bg_color]); |
974 | } | 993 | } |
975 | #ifdef __BIG_ENDIAN | 994 | #ifdef __BIG_ENDIAN |
976 | srcfmt = 0x400000 | BIT(20); | 995 | srcfmt = 0x400000 | BIT(20); |
977 | #else | 996 | #else |
978 | srcfmt = 0x400000; | 997 | srcfmt = 0x400000; |
979 | #endif | 998 | #endif |
980 | } | 999 | /* asume always image->height < 4096 */ |
1000 | if (dy + image->height > 4095) { | ||
1001 | dstbase = stride * dy; | ||
1002 | dy = 0; | ||
1003 | } | ||
1004 | /* asume always image->width < 4096 */ | ||
1005 | if (dx + image->width > 4095) { | ||
1006 | dstbase += dx * bpp >> 3; | ||
1007 | dx = 0; | ||
1008 | } | ||
981 | 1009 | ||
982 | tdfx_outl(par, SRCXY, 0); | 1010 | tdfx_outl(par, DSTBASE, dstbase); |
983 | tdfx_outl(par, DSTXY, image->dx | (image->dy << 16)); | 1011 | tdfx_outl(par, SRCXY, 0); |
984 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); | 1012 | tdfx_outl(par, DSTXY, dx | (dy << 16)); |
985 | tdfx_outl(par, SRCFORMAT, srcfmt); | 1013 | tdfx_outl(par, COMMAND_2D, |
986 | tdfx_outl(par, DSTFORMAT, dstfmt); | 1014 | COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); |
987 | tdfx_outl(par, DSTSIZE, image->width | (image->height << 16)); | 1015 | tdfx_outl(par, SRCFORMAT, srcfmt); |
1016 | tdfx_outl(par, DSTFORMAT, dstfmt); | ||
1017 | tdfx_outl(par, DSTSIZE, image->width | (image->height << 16)); | ||
988 | 1018 | ||
989 | /* A count of how many free FIFO entries we've requested. | 1019 | /* A count of how many free FIFO entries we've requested. |
990 | * When this goes negative, we need to request more. */ | 1020 | * When this goes negative, we need to request more. */ |
991 | fifo_free = 0; | 1021 | fifo_free = 0; |
992 | 1022 | ||
993 | /* Send four bytes at a time of data */ | 1023 | /* Send four bytes at a time of data */ |
994 | for (i = (size >> 2) ; i > 0; i--) { | 1024 | for (i = (size >> 2); i > 0; i--) { |
995 | if(--fifo_free < 0) { | 1025 | if (--fifo_free < 0) { |
996 | fifo_free=31; | 1026 | fifo_free = 31; |
997 | banshee_make_room(par,fifo_free); | 1027 | banshee_make_room(par, fifo_free); |
998 | } | 1028 | } |
999 | tdfx_outl(par, LAUNCH_2D,*(u32*)chardata); | 1029 | tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata); |
1000 | chardata += 4; | 1030 | chardata += 4; |
1001 | } | 1031 | } |
1002 | 1032 | ||
1003 | /* Send the leftovers now */ | 1033 | /* Send the leftovers now */ |
1004 | banshee_make_room(par,3); | 1034 | banshee_make_room(par, 3); |
1005 | i = size%4; | 1035 | switch (size % 4) { |
1006 | switch (i) { | 1036 | case 0: |
1007 | case 0: break; | 1037 | break; |
1008 | case 1: tdfx_outl(par, LAUNCH_2D,*chardata); break; | 1038 | case 1: |
1009 | case 2: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata); break; | 1039 | tdfx_outl(par, LAUNCH_2D, *chardata); |
1010 | case 3: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break; | 1040 | break; |
1041 | case 2: | ||
1042 | tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata); | ||
1043 | break; | ||
1044 | case 3: | ||
1045 | tdfx_outl(par, LAUNCH_2D, | ||
1046 | *(u16 *)chardata | (chardata[3] << 24)); | ||
1047 | break; | ||
1011 | } | 1048 | } |
1012 | } | 1049 | } |
1013 | #endif /* CONFIG_FB_3DFX_ACCEL */ | 1050 | #endif /* CONFIG_FB_3DFX_ACCEL */ |
1014 | 1051 | ||
1015 | #ifdef TDFX_HARDWARE_CURSOR | ||
1016 | static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 1052 | static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
1017 | { | 1053 | { |
1018 | struct tdfx_par *par = info->par; | 1054 | struct tdfx_par *par = info->par; |
1019 | unsigned long flags; | 1055 | u32 vidcfg; |
1020 | 1056 | ||
1021 | /* | 1057 | if (!hwcursor) |
1022 | * If the cursor is not be changed this means either we want the | 1058 | return -EINVAL; /* just to force soft_cursor() call */ |
1023 | * current cursor state (if enable is set) or we want to query what | ||
1024 | * we can do with the cursor (if enable is not set) | ||
1025 | */ | ||
1026 | if (!cursor->set) return 0; | ||
1027 | 1059 | ||
1028 | /* Too large of a cursor :-( */ | 1060 | /* Too large of a cursor or wrong bpp :-( */ |
1029 | if (cursor->image.width > 64 || cursor->image.height > 64) | 1061 | if (cursor->image.width > 64 || |
1030 | return -ENXIO; | 1062 | cursor->image.height > 64 || |
1063 | cursor->image.depth > 1) | ||
1064 | return -EINVAL; | ||
1031 | 1065 | ||
1032 | /* | 1066 | vidcfg = tdfx_inl(par, VIDPROCCFG); |
1033 | * If we are going to be changing things we should disable | 1067 | if (cursor->enable) |
1034 | * the cursor first | 1068 | tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE); |
1035 | */ | 1069 | else |
1036 | if (info->cursor.enable) { | 1070 | tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE); |
1037 | spin_lock_irqsave(&par->DAClock, flags); | ||
1038 | info->cursor.enable = 0; | ||
1039 | del_timer(&(par->hwcursor.timer)); | ||
1040 | tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable); | ||
1041 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1042 | } | ||
1043 | 1071 | ||
1044 | /* Disable the Cursor */ | 1072 | /* |
1045 | if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable) | 1073 | * If the cursor is not be changed this means either we want the |
1074 | * current cursor state (if enable is set) or we want to query what | ||
1075 | * we can do with the cursor (if enable is not set) | ||
1076 | */ | ||
1077 | if (!cursor->set) | ||
1046 | return 0; | 1078 | return 0; |
1047 | 1079 | ||
1048 | /* fix cursor color - XFree86 forgets to restore it properly */ | 1080 | /* fix cursor color - XFree86 forgets to restore it properly */ |
1049 | if (cursor->set && FB_CUR_SETCMAP) { | 1081 | if (cursor->set & FB_CUR_SETCMAP) { |
1050 | struct fb_cmap cmap = cursor->image.cmap; | 1082 | struct fb_cmap cmap = info->cmap; |
1083 | u32 bg_idx = cursor->image.bg_color; | ||
1084 | u32 fg_idx = cursor->image.fg_color; | ||
1051 | unsigned long bg_color, fg_color; | 1085 | unsigned long bg_color, fg_color; |
1052 | 1086 | ||
1053 | cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */ | 1087 | fg_color = (((u32)cmap.red[fg_idx] & 0xff00) << 8) | |
1054 | fg_color = ((cmap.red[cmap.start] << 16) | | 1088 | (((u32)cmap.green[fg_idx] & 0xff00) << 0) | |
1055 | (cmap.green[cmap.start] << 8) | | 1089 | (((u32)cmap.blue[fg_idx] & 0xff00) >> 8); |
1056 | (cmap.blue[cmap.start])); | 1090 | bg_color = (((u32)cmap.red[bg_idx] & 0xff00) << 8) | |
1057 | bg_color = ((cmap.red[cmap.start+1] << 16) | | 1091 | (((u32)cmap.green[bg_idx] & 0xff00) << 0) | |
1058 | (cmap.green[cmap.start+1] << 8) | | 1092 | (((u32)cmap.blue[bg_idx] & 0xff00) >> 8); |
1059 | (cmap.blue[cmap.start+1])); | ||
1060 | fb_copy_cmap(&cmap, &info->cursor.image.cmap); | ||
1061 | spin_lock_irqsave(&par->DAClock, flags); | ||
1062 | banshee_make_room(par, 2); | 1093 | banshee_make_room(par, 2); |
1063 | tdfx_outl(par, HWCURC0, bg_color); | 1094 | tdfx_outl(par, HWCURC0, bg_color); |
1064 | tdfx_outl(par, HWCURC1, fg_color); | 1095 | tdfx_outl(par, HWCURC1, fg_color); |
1065 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1066 | } | 1096 | } |
1067 | 1097 | ||
1068 | if (cursor->set && FB_CUR_SETPOS) { | 1098 | if (cursor->set & FB_CUR_SETPOS) { |
1069 | int x, y; | 1099 | int x = cursor->image.dx; |
1100 | int y = cursor->image.dy - info->var.yoffset; | ||
1070 | 1101 | ||
1071 | x = cursor->image.dx; | ||
1072 | y = cursor->image.dy; | ||
1073 | y -= info->var.yoffset; | ||
1074 | info->cursor.image.dx = x; | ||
1075 | info->cursor.image.dy = y; | ||
1076 | x += 63; | 1102 | x += 63; |
1077 | y += 63; | 1103 | y += 63; |
1078 | spin_lock_irqsave(&par->DAClock, flags); | ||
1079 | banshee_make_room(par, 1); | 1104 | banshee_make_room(par, 1); |
1080 | tdfx_outl(par, HWCURLOC, (y << 16) + x); | 1105 | tdfx_outl(par, HWCURLOC, (y << 16) + x); |
1081 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1082 | } | 1106 | } |
1083 | 1107 | if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) { | |
1084 | /* Not supported so we fake it */ | ||
1085 | if (cursor->set && FB_CUR_SETHOT) { | ||
1086 | info->cursor.hot.x = cursor->hot.x; | ||
1087 | info->cursor.hot.y = cursor->hot.y; | ||
1088 | } | ||
1089 | |||
1090 | if (cursor->set && FB_CUR_SETSHAPE) { | ||
1091 | /* | 1108 | /* |
1092 | * Voodoo 3 and above cards use 2 monochrome cursor patterns. | 1109 | * Voodoo 3 and above cards use 2 monochrome cursor patterns. |
1093 | * The reason is so the card can fetch 8 words at a time | 1110 | * The reason is so the card can fetch 8 words at a time |
1094 | * and are stored on chip for use for the next 8 scanlines. | 1111 | * and are stored on chip for use for the next 8 scanlines. |
1095 | * This reduces the number of times for access to draw the | 1112 | * This reduces the number of times for access to draw the |
1096 | * cursor for each screen refresh. | 1113 | * cursor for each screen refresh. |
1097 | * Each pattern is a bitmap of 64 bit wide and 64 bit high | 1114 | * Each pattern is a bitmap of 64 bit wide and 64 bit high |
1098 | * (total of 8192 bits or 1024 Kbytes). The two patterns are | 1115 | * (total of 8192 bits or 1024 bytes). The two patterns are |
1099 | * stored in such a way that pattern 0 always resides in the | 1116 | * stored in such a way that pattern 0 always resides in the |
1100 | * lower half (least significant 64 bits) of a 128 bit word | 1117 | * lower half (least significant 64 bits) of a 128 bit word |
1101 | * and pattern 1 the upper half. If you examine the data of | 1118 | * and pattern 1 the upper half. If you examine the data of |
@@ -1106,50 +1123,54 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1106 | * (128 bits) which is the maximum cursor width times two for | 1123 | * (128 bits) which is the maximum cursor width times two for |
1107 | * the two monochrome patterns. | 1124 | * the two monochrome patterns. |
1108 | */ | 1125 | */ |
1109 | u8 *cursorbase = (u8 *) info->cursor.image.data; | 1126 | u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len; |
1110 | char *bitmap = (char *)cursor->image.data; | 1127 | u8 *bitmap = (u8 *)cursor->image.data; |
1111 | char *mask = (char *) cursor->mask; | 1128 | u8 *mask = (u8 *)cursor->mask; |
1112 | int i, j, k, h = 0; | 1129 | int i; |
1113 | 1130 | ||
1114 | for (i = 0; i < 64; i++) { | 1131 | fb_memset(cursorbase, 0, 1024); |
1115 | if (i < cursor->image.height) { | 1132 | |
1116 | j = (cursor->image.width + 7) >> 3; | 1133 | for (i = 0; i < cursor->image.height; i++) { |
1117 | k = 8 - j; | 1134 | int h = 0; |
1118 | 1135 | int j = (cursor->image.width + 7) >> 3; | |
1119 | for (;j > 0; j--) { | 1136 | |
1120 | /* Pattern 0. Copy the cursor bitmap to it */ | 1137 | for (; j > 0; j--) { |
1121 | fb_writeb(*bitmap, cursorbase + h); | 1138 | u8 data = *mask ^ *bitmap; |
1122 | bitmap++; | 1139 | if (cursor->rop == ROP_COPY) |
1123 | /* Pattern 1. Copy the cursor mask to it */ | 1140 | data = *mask & *bitmap; |
1124 | fb_writeb(*mask, cursorbase + h + 8); | 1141 | /* Pattern 0. Copy the cursor mask to it */ |
1125 | mask++; | 1142 | fb_writeb(*mask, cursorbase + h); |
1126 | h++; | 1143 | mask++; |
1127 | } | 1144 | /* Pattern 1. Copy the cursor bitmap to it */ |
1128 | for (;k > 0; k--) { | 1145 | fb_writeb(data, cursorbase + h + 8); |
1129 | fb_writeb(0, cursorbase + h); | 1146 | bitmap++; |
1130 | fb_writeb(~0, cursorbase + h + 8); | 1147 | h++; |
1131 | h++; | ||
1132 | } | ||
1133 | } else { | ||
1134 | fb_writel(0, cursorbase + h); | ||
1135 | fb_writel(0, cursorbase + h + 4); | ||
1136 | fb_writel(~0, cursorbase + h + 8); | ||
1137 | fb_writel(~0, cursorbase + h + 12); | ||
1138 | h += 16; | ||
1139 | } | 1148 | } |
1149 | cursorbase += 16; | ||
1140 | } | 1150 | } |
1141 | } | 1151 | } |
1142 | /* Turn the cursor on */ | ||
1143 | cursor->enable = 1; | ||
1144 | info->cursor = *cursor; | ||
1145 | mod_timer(&par->hwcursor.timer, jiffies+HZ/2); | ||
1146 | spin_lock_irqsave(&par->DAClock, flags); | ||
1147 | banshee_make_room(par, 1); | ||
1148 | tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable); | ||
1149 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1150 | return 0; | 1152 | return 0; |
1151 | } | 1153 | } |
1154 | |||
1155 | static struct fb_ops tdfxfb_ops = { | ||
1156 | .owner = THIS_MODULE, | ||
1157 | .fb_check_var = tdfxfb_check_var, | ||
1158 | .fb_set_par = tdfxfb_set_par, | ||
1159 | .fb_setcolreg = tdfxfb_setcolreg, | ||
1160 | .fb_blank = tdfxfb_blank, | ||
1161 | .fb_pan_display = tdfxfb_pan_display, | ||
1162 | .fb_sync = banshee_wait_idle, | ||
1163 | .fb_cursor = tdfxfb_cursor, | ||
1164 | #ifdef CONFIG_FB_3DFX_ACCEL | ||
1165 | .fb_fillrect = tdfxfb_fillrect, | ||
1166 | .fb_copyarea = tdfxfb_copyarea, | ||
1167 | .fb_imageblit = tdfxfb_imageblit, | ||
1168 | #else | ||
1169 | .fb_fillrect = cfb_fillrect, | ||
1170 | .fb_copyarea = cfb_copyarea, | ||
1171 | .fb_imageblit = cfb_imageblit, | ||
1152 | #endif | 1172 | #endif |
1173 | }; | ||
1153 | 1174 | ||
1154 | /** | 1175 | /** |
1155 | * tdfxfb_probe - Device Initializiation | 1176 | * tdfxfb_probe - Device Initializiation |
@@ -1161,14 +1182,15 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1161 | * | 1182 | * |
1162 | */ | 1183 | */ |
1163 | static int __devinit tdfxfb_probe(struct pci_dev *pdev, | 1184 | static int __devinit tdfxfb_probe(struct pci_dev *pdev, |
1164 | const struct pci_device_id *id) | 1185 | const struct pci_device_id *id) |
1165 | { | 1186 | { |
1166 | struct tdfx_par *default_par; | 1187 | struct tdfx_par *default_par; |
1167 | struct fb_info *info; | 1188 | struct fb_info *info; |
1168 | int err, lpitch; | 1189 | int err, lpitch; |
1169 | 1190 | ||
1170 | if ((err = pci_enable_device(pdev))) { | 1191 | err = pci_enable_device(pdev); |
1171 | printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err); | 1192 | if (err) { |
1193 | printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err); | ||
1172 | return err; | 1194 | return err; |
1173 | } | 1195 | } |
1174 | 1196 | ||
@@ -1176,139 +1198,145 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1176 | 1198 | ||
1177 | if (!info) | 1199 | if (!info) |
1178 | return -ENOMEM; | 1200 | return -ENOMEM; |
1179 | 1201 | ||
1180 | default_par = info->par; | 1202 | default_par = info->par; |
1181 | 1203 | ||
1182 | /* Configure the default fb_fix_screeninfo first */ | 1204 | /* Configure the default fb_fix_screeninfo first */ |
1183 | switch (pdev->device) { | 1205 | switch (pdev->device) { |
1184 | case PCI_DEVICE_ID_3DFX_BANSHEE: | 1206 | case PCI_DEVICE_ID_3DFX_BANSHEE: |
1185 | strcat(tdfx_fix.id, " Banshee"); | 1207 | strcat(tdfx_fix.id, " Banshee"); |
1186 | default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; | 1208 | default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; |
1187 | break; | 1209 | break; |
1188 | case PCI_DEVICE_ID_3DFX_VOODOO3: | 1210 | case PCI_DEVICE_ID_3DFX_VOODOO3: |
1189 | strcat(tdfx_fix.id, " Voodoo3"); | 1211 | strcat(tdfx_fix.id, " Voodoo3"); |
1190 | default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; | 1212 | default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; |
1191 | break; | 1213 | break; |
1192 | case PCI_DEVICE_ID_3DFX_VOODOO5: | 1214 | case PCI_DEVICE_ID_3DFX_VOODOO5: |
1193 | strcat(tdfx_fix.id, " Voodoo5"); | 1215 | strcat(tdfx_fix.id, " Voodoo5"); |
1194 | default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; | 1216 | default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; |
1195 | break; | 1217 | break; |
1196 | } | 1218 | } |
1197 | 1219 | ||
1198 | tdfx_fix.mmio_start = pci_resource_start(pdev, 0); | 1220 | tdfx_fix.mmio_start = pci_resource_start(pdev, 0); |
1199 | tdfx_fix.mmio_len = pci_resource_len(pdev, 0); | 1221 | tdfx_fix.mmio_len = pci_resource_len(pdev, 0); |
1200 | default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); | 1222 | if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len, |
1201 | if (!default_par->regbase_virt) { | 1223 | "tdfx regbase")) { |
1202 | printk("fb: Can't remap %s register area.\n", tdfx_fix.id); | 1224 | printk(KERN_ERR "tdfxfb: Can't reserve regbase\n"); |
1203 | goto out_err; | 1225 | goto out_err; |
1204 | } | 1226 | } |
1205 | 1227 | ||
1206 | if (!request_mem_region(pci_resource_start(pdev, 0), | 1228 | default_par->regbase_virt = |
1207 | pci_resource_len(pdev, 0), "tdfx regbase")) { | 1229 | ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); |
1208 | printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n"); | 1230 | if (!default_par->regbase_virt) { |
1209 | goto out_err; | 1231 | printk(KERN_ERR "fb: Can't remap %s register area.\n", |
1210 | } | 1232 | tdfx_fix.id); |
1233 | goto out_err_regbase; | ||
1234 | } | ||
1211 | 1235 | ||
1212 | tdfx_fix.smem_start = pci_resource_start(pdev, 1); | 1236 | tdfx_fix.smem_start = pci_resource_start(pdev, 1); |
1213 | if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { | 1237 | tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device); |
1214 | printk("fb: Can't count %s memory.\n", tdfx_fix.id); | 1238 | if (!tdfx_fix.smem_len) { |
1215 | release_mem_region(pci_resource_start(pdev, 0), | 1239 | printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id); |
1216 | pci_resource_len(pdev, 0)); | 1240 | goto out_err_regbase; |
1217 | goto out_err; | ||
1218 | } | 1241 | } |
1219 | 1242 | ||
1220 | if (!request_mem_region(pci_resource_start(pdev, 1), | 1243 | if (!request_mem_region(tdfx_fix.smem_start, |
1221 | pci_resource_len(pdev, 1), "tdfx smem")) { | 1244 | pci_resource_len(pdev, 1), "tdfx smem")) { |
1222 | printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); | 1245 | printk(KERN_ERR "tdfxfb: Can't reserve smem\n"); |
1223 | release_mem_region(pci_resource_start(pdev, 0), | 1246 | goto out_err_regbase; |
1224 | pci_resource_len(pdev, 0)); | ||
1225 | goto out_err; | ||
1226 | } | 1247 | } |
1227 | 1248 | ||
1228 | info->screen_base = ioremap_nocache(tdfx_fix.smem_start, | 1249 | info->screen_base = ioremap_nocache(tdfx_fix.smem_start, |
1229 | tdfx_fix.smem_len); | 1250 | tdfx_fix.smem_len); |
1230 | if (!info->screen_base) { | 1251 | if (!info->screen_base) { |
1231 | printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); | 1252 | printk(KERN_ERR "fb: Can't remap %s framebuffer.\n", |
1232 | release_mem_region(pci_resource_start(pdev, 1), | 1253 | tdfx_fix.id); |
1233 | pci_resource_len(pdev, 1)); | 1254 | goto out_err_screenbase; |
1234 | release_mem_region(pci_resource_start(pdev, 0), | ||
1235 | pci_resource_len(pdev, 0)); | ||
1236 | goto out_err; | ||
1237 | } | 1255 | } |
1238 | 1256 | ||
1239 | default_par->iobase = pci_resource_start(pdev, 2); | 1257 | default_par->iobase = pci_resource_start(pdev, 2); |
1240 | 1258 | ||
1241 | if (!request_region(pci_resource_start(pdev, 2), | 1259 | if (!request_region(pci_resource_start(pdev, 2), |
1242 | pci_resource_len(pdev, 2), "tdfx iobase")) { | 1260 | pci_resource_len(pdev, 2), "tdfx iobase")) { |
1243 | printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); | 1261 | printk(KERN_ERR "tdfxfb: Can't reserve iobase\n"); |
1244 | release_mem_region(pci_resource_start(pdev, 1), | 1262 | goto out_err_screenbase; |
1245 | pci_resource_len(pdev, 1)); | ||
1246 | release_mem_region(pci_resource_start(pdev, 0), | ||
1247 | pci_resource_len(pdev, 0)); | ||
1248 | goto out_err; | ||
1249 | } | 1263 | } |
1250 | 1264 | ||
1251 | printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); | 1265 | printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id, |
1266 | tdfx_fix.smem_len >> 10); | ||
1267 | |||
1268 | default_par->mtrr_handle = -1; | ||
1269 | if (!nomtrr) | ||
1270 | default_par->mtrr_handle = | ||
1271 | mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len, | ||
1272 | MTRR_TYPE_WRCOMB, 1); | ||
1252 | 1273 | ||
1253 | tdfx_fix.ypanstep = nopan ? 0 : 1; | 1274 | tdfx_fix.ypanstep = nopan ? 0 : 1; |
1254 | tdfx_fix.ywrapstep = nowrap ? 0 : 1; | 1275 | tdfx_fix.ywrapstep = nowrap ? 0 : 1; |
1255 | 1276 | ||
1256 | info->fbops = &tdfxfb_ops; | 1277 | info->fbops = &tdfxfb_ops; |
1257 | info->fix = tdfx_fix; | 1278 | info->fix = tdfx_fix; |
1258 | info->pseudo_palette = default_par->palette; | 1279 | info->pseudo_palette = default_par->palette; |
1259 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 1280 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
1260 | #ifdef CONFIG_FB_3DFX_ACCEL | 1281 | #ifdef CONFIG_FB_3DFX_ACCEL |
1261 | info->flags |= FBINFO_HWACCEL_FILLRECT | | 1282 | info->flags |= FBINFO_HWACCEL_FILLRECT | |
1262 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; | 1283 | FBINFO_HWACCEL_COPYAREA | |
1284 | FBINFO_HWACCEL_IMAGEBLIT | | ||
1285 | FBINFO_READS_FAST; | ||
1263 | #endif | 1286 | #endif |
1287 | /* reserve 8192 bits for cursor */ | ||
1288 | /* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */ | ||
1289 | if (hwcursor) | ||
1290 | info->fix.smem_len = (info->fix.smem_len - 1024) & | ||
1291 | (PAGE_MASK << 1); | ||
1264 | 1292 | ||
1265 | if (!mode_option) | 1293 | if (!mode_option) |
1266 | mode_option = "640x480@60"; | 1294 | mode_option = "640x480@60"; |
1267 | 1295 | ||
1268 | err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); | 1296 | err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); |
1269 | if (!err || err == 4) | 1297 | if (!err || err == 4) |
1270 | info->var = tdfx_var; | 1298 | info->var = tdfx_var; |
1271 | 1299 | ||
1272 | /* maximize virtual vertical length */ | 1300 | /* maximize virtual vertical length */ |
1273 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); | 1301 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); |
1274 | info->var.yres_virtual = info->fix.smem_len/lpitch; | 1302 | info->var.yres_virtual = info->fix.smem_len / lpitch; |
1275 | if (info->var.yres_virtual < info->var.yres) | 1303 | if (info->var.yres_virtual < info->var.yres) |
1276 | goto out_err; | 1304 | goto out_err_iobase; |
1277 | |||
1278 | #ifdef CONFIG_FB_3DFX_ACCEL | ||
1279 | /* | ||
1280 | * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts | ||
1281 | * during scrolling. This is only present if 2D acceleration is | ||
1282 | * enabled. | ||
1283 | */ | ||
1284 | if (info->var.yres_virtual > 4096) | ||
1285 | info->var.yres_virtual = 4096; | ||
1286 | #endif /* CONFIG_FB_3DFX_ACCEL */ | ||
1287 | 1305 | ||
1288 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | 1306 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
1289 | printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); | 1307 | printk(KERN_ERR "tdfxfb: Can't allocate color map\n"); |
1290 | goto out_err; | 1308 | goto out_err_iobase; |
1291 | } | 1309 | } |
1292 | 1310 | ||
1293 | if (register_framebuffer(info) < 0) { | 1311 | if (register_framebuffer(info) < 0) { |
1294 | printk("tdfxfb: can't register framebuffer\n"); | 1312 | printk(KERN_ERR "tdfxfb: can't register framebuffer\n"); |
1295 | fb_dealloc_cmap(&info->cmap); | 1313 | fb_dealloc_cmap(&info->cmap); |
1296 | goto out_err; | 1314 | goto out_err_iobase; |
1297 | } | 1315 | } |
1298 | /* | 1316 | /* |
1299 | * Our driver data | 1317 | * Our driver data |
1300 | */ | 1318 | */ |
1301 | pci_set_drvdata(pdev, info); | 1319 | pci_set_drvdata(pdev, info); |
1302 | return 0; | 1320 | return 0; |
1303 | 1321 | ||
1304 | out_err: | 1322 | out_err_iobase: |
1323 | if (default_par->mtrr_handle >= 0) | ||
1324 | mtrr_del(default_par->mtrr_handle, info->fix.smem_start, | ||
1325 | info->fix.smem_len); | ||
1326 | release_mem_region(pci_resource_start(pdev, 2), | ||
1327 | pci_resource_len(pdev, 2)); | ||
1328 | out_err_screenbase: | ||
1329 | if (info->screen_base) | ||
1330 | iounmap(info->screen_base); | ||
1331 | release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1)); | ||
1332 | out_err_regbase: | ||
1305 | /* | 1333 | /* |
1306 | * Cleanup after anything that was remapped/allocated. | 1334 | * Cleanup after anything that was remapped/allocated. |
1307 | */ | 1335 | */ |
1308 | if (default_par->regbase_virt) | 1336 | if (default_par->regbase_virt) |
1309 | iounmap(default_par->regbase_virt); | 1337 | iounmap(default_par->regbase_virt); |
1310 | if (info->screen_base) | 1338 | release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len); |
1311 | iounmap(info->screen_base); | 1339 | out_err: |
1312 | framebuffer_release(info); | 1340 | framebuffer_release(info); |
1313 | return -ENXIO; | 1341 | return -ENXIO; |
1314 | } | 1342 | } |
@@ -1316,7 +1344,7 @@ out_err: | |||
1316 | #ifndef MODULE | 1344 | #ifndef MODULE |
1317 | static void tdfxfb_setup(char *options) | 1345 | static void tdfxfb_setup(char *options) |
1318 | { | 1346 | { |
1319 | char* this_opt; | 1347 | char *this_opt; |
1320 | 1348 | ||
1321 | if (!options || !*options) | 1349 | if (!options || !*options) |
1322 | return; | 1350 | return; |
@@ -1324,10 +1352,16 @@ static void tdfxfb_setup(char *options) | |||
1324 | while ((this_opt = strsep(&options, ",")) != NULL) { | 1352 | while ((this_opt = strsep(&options, ",")) != NULL) { |
1325 | if (!*this_opt) | 1353 | if (!*this_opt) |
1326 | continue; | 1354 | continue; |
1327 | if(!strcmp(this_opt, "nopan")) { | 1355 | if (!strcmp(this_opt, "nopan")) { |
1328 | nopan = 1; | 1356 | nopan = 1; |
1329 | } else if(!strcmp(this_opt, "nowrap")) { | 1357 | } else if (!strcmp(this_opt, "nowrap")) { |
1330 | nowrap = 1; | 1358 | nowrap = 1; |
1359 | } else if (!strncmp(this_opt, "hwcursor=", 9)) { | ||
1360 | hwcursor = simple_strtoul(this_opt + 9, NULL, 0); | ||
1361 | #ifdef CONFIG_MTRR | ||
1362 | } else if (!strncmp(this_opt, "nomtrr", 6)) { | ||
1363 | nomtrr = 1; | ||
1364 | #endif | ||
1331 | } else { | 1365 | } else { |
1332 | mode_option = this_opt; | 1366 | mode_option = this_opt; |
1333 | } | 1367 | } |
@@ -1350,6 +1384,9 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev) | |||
1350 | struct tdfx_par *par = info->par; | 1384 | struct tdfx_par *par = info->par; |
1351 | 1385 | ||
1352 | unregister_framebuffer(info); | 1386 | unregister_framebuffer(info); |
1387 | if (par->mtrr_handle >= 0) | ||
1388 | mtrr_del(par->mtrr_handle, info->fix.smem_start, | ||
1389 | info->fix.smem_len); | ||
1353 | iounmap(par->regbase_virt); | 1390 | iounmap(par->regbase_virt); |
1354 | iounmap(info->screen_base); | 1391 | iounmap(info->screen_base); |
1355 | 1392 | ||
@@ -1374,17 +1411,25 @@ static int __init tdfxfb_init(void) | |||
1374 | 1411 | ||
1375 | tdfxfb_setup(option); | 1412 | tdfxfb_setup(option); |
1376 | #endif | 1413 | #endif |
1377 | return pci_register_driver(&tdfxfb_driver); | 1414 | return pci_register_driver(&tdfxfb_driver); |
1378 | } | 1415 | } |
1379 | 1416 | ||
1380 | static void __exit tdfxfb_exit(void) | 1417 | static void __exit tdfxfb_exit(void) |
1381 | { | 1418 | { |
1382 | pci_unregister_driver(&tdfxfb_driver); | 1419 | pci_unregister_driver(&tdfxfb_driver); |
1383 | } | 1420 | } |
1384 | 1421 | ||
1385 | MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); | 1422 | MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); |
1386 | MODULE_DESCRIPTION("3Dfx framebuffer device driver"); | 1423 | MODULE_DESCRIPTION("3Dfx framebuffer device driver"); |
1387 | MODULE_LICENSE("GPL"); | 1424 | MODULE_LICENSE("GPL"); |
1388 | 1425 | ||
1426 | module_param(hwcursor, int, 0644); | ||
1427 | MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " | ||
1428 | "(1=enable, 0=disable, default=1)"); | ||
1429 | #ifdef CONFIG_MTRR | ||
1430 | module_param(nomtrr, bool, 0); | ||
1431 | MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)"); | ||
1432 | #endif | ||
1433 | |||
1389 | module_init(tdfxfb_init); | 1434 | module_init(tdfxfb_init); |
1390 | module_exit(tdfxfb_exit); | 1435 | module_exit(tdfxfb_exit); |
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index d292a37ec7d6..680642c089c9 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Copyright (C) 1997 Geert Uytterhoeven | 5 | * Copyright (C) 1997 Geert Uytterhoeven |
6 | * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha | 6 | * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha |
7 | * Copyright (C) 2002 Richard Henderson | 7 | * Copyright (C) 2002 Richard Henderson |
8 | * Copyright (C) 2006 Maciej W. Rozycki | 8 | * Copyright (C) 2006, 2007 Maciej W. Rozycki |
9 | * | 9 | * |
10 | * This file is subject to the terms and conditions of the GNU General Public | 10 | * This file is subject to the terms and conditions of the GNU General Public |
11 | * License. See the file COPYING in the main directory of this archive for | 11 | * License. See the file COPYING in the main directory of this archive for |
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/bitrev.h> | 15 | #include <linux/bitrev.h> |
16 | #include <linux/compiler.h> | ||
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
18 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
@@ -636,15 +637,6 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) | |||
636 | 637 | ||
637 | is8bpp = info->var.bits_per_pixel == 8; | 638 | is8bpp = info->var.bits_per_pixel == 8; |
638 | 639 | ||
639 | /* For copies that aren't pixel expansion, there's little we | ||
640 | can do better than the generic code. */ | ||
641 | /* ??? There is a DMA write mode; I wonder if that could be | ||
642 | made to pull the data from the image buffer... */ | ||
643 | if (image->depth > 1) { | ||
644 | cfb_imageblit(info, image); | ||
645 | return; | ||
646 | } | ||
647 | |||
648 | dx = image->dx; | 640 | dx = image->dx; |
649 | dy = image->dy; | 641 | dy = image->dy; |
650 | width = image->width; | 642 | width = image->width; |
@@ -654,6 +646,9 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) | |||
654 | line_length = info->fix.line_length; | 646 | line_length = info->fix.line_length; |
655 | rincr = (width + 7) / 8; | 647 | rincr = (width + 7) / 8; |
656 | 648 | ||
649 | /* A shift below cannot cope with. */ | ||
650 | if (unlikely(width == 0)) | ||
651 | return; | ||
657 | /* Crop the image to the screen. */ | 652 | /* Crop the image to the screen. */ |
658 | if (dx > vxres || dy > vyres) | 653 | if (dx > vxres || dy > vyres) |
659 | return; | 654 | return; |
@@ -709,9 +704,10 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) | |||
709 | unsigned long bwidth; | 704 | unsigned long bwidth; |
710 | 705 | ||
711 | /* Handle common case of imaging a single character, in | 706 | /* Handle common case of imaging a single character, in |
712 | a font less than 32 pixels wide. */ | 707 | a font less than or 32 pixels wide. */ |
713 | 708 | ||
714 | pixelmask = (1 << width) - 1; | 709 | /* Avoid a shift by 32; width > 0 implied. */ |
710 | pixelmask = (2ul << (width - 1)) - 1; | ||
715 | pixelmask <<= shift; | 711 | pixelmask <<= shift; |
716 | __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); | 712 | __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); |
717 | wmb(); | 713 | wmb(); |
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index c699864b6f4a..70fb4ee2b421 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c | |||
@@ -1,18 +1,19 @@ | |||
1 | /* | 1 | /* |
2 | * Frame buffer driver for Trident Blade and Image series | 2 | * Frame buffer driver for Trident Blade and Image series |
3 | * | 3 | * |
4 | * Copyright 2001,2002 - Jani Monoses <jani@iv.ro> | 4 | * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * CREDITS:(in order of appearance) | 7 | * CREDITS:(in order of appearance) |
8 | * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video | 8 | * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video |
9 | * Special thanks ;) to Mattia Crivellini <tia@mclink.it> | 9 | * Special thanks ;) to Mattia Crivellini <tia@mclink.it> |
10 | * much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane | 10 | * much inspired by the XFree86 4.x Trident driver sources |
11 | * the FreeVGA project | 11 | * by Alan Hourihane the FreeVGA project |
12 | * Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions | 12 | * Francesco Salvestrini <salvestrini@users.sf.net> XP support, |
13 | * code, suggestions | ||
13 | * TODO: | 14 | * TODO: |
14 | * timing value tweaking so it looks good on every monitor in every mode | 15 | * timing value tweaking so it looks good on every monitor in every mode |
15 | * TGUI acceleration | 16 | * TGUI acceleration |
16 | */ | 17 | */ |
17 | 18 | ||
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -26,11 +27,11 @@ | |||
26 | #define VERSION "0.7.8-NEWAPI" | 27 | #define VERSION "0.7.8-NEWAPI" |
27 | 28 | ||
28 | struct tridentfb_par { | 29 | struct tridentfb_par { |
29 | int vclk; //in MHz | 30 | int vclk; /* in MHz */ |
30 | void __iomem * io_virt; //iospace virtual memory address | 31 | void __iomem *io_virt; /* iospace virtual memory address */ |
31 | }; | 32 | }; |
32 | 33 | ||
33 | static unsigned char eng_oper; //engine operation... | 34 | static unsigned char eng_oper; /* engine operation... */ |
34 | static struct fb_ops tridentfb_ops; | 35 | static struct fb_ops tridentfb_ops; |
35 | 36 | ||
36 | static struct tridentfb_par default_par; | 37 | static struct tridentfb_par default_par; |
@@ -39,11 +40,10 @@ static struct tridentfb_par default_par; | |||
39 | static struct fb_info fb_info; | 40 | static struct fb_info fb_info; |
40 | static u32 pseudo_pal[16]; | 41 | static u32 pseudo_pal[16]; |
41 | 42 | ||
42 | |||
43 | static struct fb_var_screeninfo default_var; | 43 | static struct fb_var_screeninfo default_var; |
44 | 44 | ||
45 | static struct fb_fix_screeninfo tridentfb_fix = { | 45 | static struct fb_fix_screeninfo tridentfb_fix = { |
46 | .id = "Trident", | 46 | .id = "Trident", |
47 | .type = FB_TYPE_PACKED_PIXELS, | 47 | .type = FB_TYPE_PACKED_PIXELS, |
48 | .ypanstep = 1, | 48 | .ypanstep = 1, |
49 | .visual = FB_VISUAL_PSEUDOCOLOR, | 49 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -55,11 +55,10 @@ static int chip_id; | |||
55 | static int defaultaccel; | 55 | static int defaultaccel; |
56 | static int displaytype; | 56 | static int displaytype; |
57 | 57 | ||
58 | |||
59 | /* defaults which are normally overriden by user values */ | 58 | /* defaults which are normally overriden by user values */ |
60 | 59 | ||
61 | /* video mode */ | 60 | /* video mode */ |
62 | static char * mode = "640x480"; | 61 | static char *mode = "640x480"; |
63 | static int bpp = 8; | 62 | static int bpp = 8; |
64 | 63 | ||
65 | static int noaccel; | 64 | static int noaccel; |
@@ -74,7 +73,6 @@ static int memsize; | |||
74 | static int memdiff; | 73 | static int memdiff; |
75 | static int nativex; | 74 | static int nativex; |
76 | 75 | ||
77 | |||
78 | module_param(mode, charp, 0); | 76 | module_param(mode, charp, 0); |
79 | module_param(bpp, int, 0); | 77 | module_param(bpp, int, 0); |
80 | module_param(center, int, 0); | 78 | module_param(center, int, 0); |
@@ -86,88 +84,85 @@ module_param(nativex, int, 0); | |||
86 | module_param(fp, int, 0); | 84 | module_param(fp, int, 0); |
87 | module_param(crt, int, 0); | 85 | module_param(crt, int, 0); |
88 | 86 | ||
89 | |||
90 | static int chip3D; | 87 | static int chip3D; |
91 | static int chipcyber; | 88 | static int chipcyber; |
92 | 89 | ||
93 | static int is3Dchip(int id) | 90 | static int is3Dchip(int id) |
94 | { | 91 | { |
95 | return ((id == BLADE3D) || (id == CYBERBLADEE4) || | 92 | return ((id == BLADE3D) || (id == CYBERBLADEE4) || |
96 | (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) || | 93 | (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) || |
97 | (id == CYBER9397) || (id == CYBER9397DVD) || | 94 | (id == CYBER9397) || (id == CYBER9397DVD) || |
98 | (id == CYBER9520) || (id == CYBER9525DVD) || | 95 | (id == CYBER9520) || (id == CYBER9525DVD) || |
99 | (id == IMAGE975) || (id == IMAGE985) || | 96 | (id == IMAGE975) || (id == IMAGE985) || |
100 | (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) || | 97 | (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) || |
101 | (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) || | 98 | (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) || |
102 | (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) || | 99 | (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) || |
103 | (id == CYBERBLADEXPAi1)); | 100 | (id == CYBERBLADEXPAi1)); |
104 | } | 101 | } |
105 | 102 | ||
106 | static int iscyber(int id) | 103 | static int iscyber(int id) |
107 | { | 104 | { |
108 | switch (id) { | 105 | switch (id) { |
109 | case CYBER9388: | 106 | case CYBER9388: |
110 | case CYBER9382: | 107 | case CYBER9382: |
111 | case CYBER9385: | 108 | case CYBER9385: |
112 | case CYBER9397: | 109 | case CYBER9397: |
113 | case CYBER9397DVD: | 110 | case CYBER9397DVD: |
114 | case CYBER9520: | 111 | case CYBER9520: |
115 | case CYBER9525DVD: | 112 | case CYBER9525DVD: |
116 | case CYBERBLADEE4: | 113 | case CYBERBLADEE4: |
117 | case CYBERBLADEi7D: | 114 | case CYBERBLADEi7D: |
118 | case CYBERBLADEi1: | 115 | case CYBERBLADEi1: |
119 | case CYBERBLADEi1D: | 116 | case CYBERBLADEi1D: |
120 | case CYBERBLADEAi1: | 117 | case CYBERBLADEAi1: |
121 | case CYBERBLADEAi1D: | 118 | case CYBERBLADEAi1D: |
122 | case CYBERBLADEXPAi1: | 119 | case CYBERBLADEXPAi1: |
123 | return 1; | 120 | return 1; |
124 | |||
125 | case CYBER9320: | ||
126 | case TGUI9660: | ||
127 | case IMAGE975: | ||
128 | case IMAGE985: | ||
129 | case BLADE3D: | ||
130 | case CYBERBLADEi7: /* VIA MPV4 integrated version */ | ||
131 | 121 | ||
132 | default: | 122 | case CYBER9320: |
133 | /* case CYBERBLDAEXPm8: Strange */ | 123 | case TGUI9660: |
134 | /* case CYBERBLDAEXPm16: Strange */ | 124 | case IMAGE975: |
135 | return 0; | 125 | case IMAGE985: |
126 | case BLADE3D: | ||
127 | case CYBERBLADEi7: /* VIA MPV4 integrated version */ | ||
128 | |||
129 | default: | ||
130 | /* case CYBERBLDAEXPm8: Strange */ | ||
131 | /* case CYBERBLDAEXPm16: Strange */ | ||
132 | return 0; | ||
136 | } | 133 | } |
137 | } | 134 | } |
138 | 135 | ||
139 | #define CRT 0x3D0 //CRTC registers offset for color display | 136 | #define CRT 0x3D0 /* CRTC registers offset for color display */ |
140 | 137 | ||
141 | #ifndef TRIDENT_MMIO | 138 | #ifndef TRIDENT_MMIO |
142 | #define TRIDENT_MMIO 1 | 139 | #define TRIDENT_MMIO 1 |
143 | #endif | 140 | #endif |
144 | 141 | ||
145 | #if TRIDENT_MMIO | 142 | #if TRIDENT_MMIO |
146 | #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg) | 143 | #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg) |
147 | #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg) | 144 | #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg) |
148 | #else | 145 | #else |
149 | #define t_outb(val,reg) outb(val,reg) | 146 | #define t_outb(val, reg) outb(val, reg) |
150 | #define t_inb(reg) inb(reg) | 147 | #define t_inb(reg) inb(reg) |
151 | #endif | 148 | #endif |
152 | 149 | ||
153 | 150 | ||
154 | static struct accel_switch { | 151 | static struct accel_switch { |
155 | void (*init_accel)(int,int); | 152 | void (*init_accel) (int, int); |
156 | void (*wait_engine)(void); | 153 | void (*wait_engine) (void); |
157 | void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32); | 154 | void (*fill_rect) (u32, u32, u32, u32, u32, u32); |
158 | void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32); | 155 | void (*copy_rect) (u32, u32, u32, u32, u32, u32); |
159 | } *acc; | 156 | } *acc; |
160 | 157 | ||
161 | #define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) | 158 | #define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) |
162 | #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r) | 159 | #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r) |
163 | 160 | ||
164 | |||
165 | |||
166 | /* | 161 | /* |
167 | * Blade specific acceleration. | 162 | * Blade specific acceleration. |
168 | */ | 163 | */ |
169 | 164 | ||
170 | #define point(x,y) ((y)<<16|(x)) | 165 | #define point(x, y) ((y) << 16 | (x)) |
171 | #define STA 0x2120 | 166 | #define STA 0x2120 |
172 | #define CMD 0x2144 | 167 | #define CMD 0x2144 |
173 | #define ROP 0x2148 | 168 | #define ROP 0x2148 |
@@ -179,64 +174,71 @@ static struct accel_switch { | |||
179 | 174 | ||
180 | #define ROP_S 0xCC | 175 | #define ROP_S 0xCC |
181 | 176 | ||
182 | static void blade_init_accel(int pitch,int bpp) | 177 | static void blade_init_accel(int pitch, int bpp) |
183 | { | 178 | { |
184 | int v1 = (pitch>>3)<<20; | 179 | int v1 = (pitch >> 3) << 20; |
185 | int tmp = 0,v2; | 180 | int tmp = 0, v2; |
186 | switch (bpp) { | 181 | switch (bpp) { |
187 | case 8:tmp = 0;break; | 182 | case 8: |
188 | case 15:tmp = 5;break; | 183 | tmp = 0; |
189 | case 16:tmp = 1;break; | 184 | break; |
190 | case 24: | 185 | case 15: |
191 | case 32:tmp = 2;break; | 186 | tmp = 5; |
187 | break; | ||
188 | case 16: | ||
189 | tmp = 1; | ||
190 | break; | ||
191 | case 24: | ||
192 | case 32: | ||
193 | tmp = 2; | ||
194 | break; | ||
192 | } | 195 | } |
193 | v2 = v1 | (tmp<<29); | 196 | v2 = v1 | (tmp << 29); |
194 | writemmr(0x21C0,v2); | 197 | writemmr(0x21C0, v2); |
195 | writemmr(0x21C4,v2); | 198 | writemmr(0x21C4, v2); |
196 | writemmr(0x21B8,v2); | 199 | writemmr(0x21B8, v2); |
197 | writemmr(0x21BC,v2); | 200 | writemmr(0x21BC, v2); |
198 | writemmr(0x21D0,v1); | 201 | writemmr(0x21D0, v1); |
199 | writemmr(0x21D4,v1); | 202 | writemmr(0x21D4, v1); |
200 | writemmr(0x21C8,v1); | 203 | writemmr(0x21C8, v1); |
201 | writemmr(0x21CC,v1); | 204 | writemmr(0x21CC, v1); |
202 | writemmr(0x216C,0); | 205 | writemmr(0x216C, 0); |
203 | } | 206 | } |
204 | 207 | ||
205 | static void blade_wait_engine(void) | 208 | static void blade_wait_engine(void) |
206 | { | 209 | { |
207 | while(readmmr(STA) & 0xFA800000); | 210 | while (readmmr(STA) & 0xFA800000) ; |
208 | } | 211 | } |
209 | 212 | ||
210 | static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) | 213 | static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) |
211 | { | 214 | { |
212 | writemmr(CLR,c); | 215 | writemmr(CLR, c); |
213 | writemmr(ROP,rop ? 0x66:ROP_S); | 216 | writemmr(ROP, rop ? 0x66 : ROP_S); |
214 | writemmr(CMD,0x20000000|1<<19|1<<4|2<<2); | 217 | writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); |
215 | 218 | ||
216 | writemmr(DR1,point(x,y)); | 219 | writemmr(DR1, point(x, y)); |
217 | writemmr(DR2,point(x+w-1,y+h-1)); | 220 | writemmr(DR2, point(x + w - 1, y + h - 1)); |
218 | } | 221 | } |
219 | 222 | ||
220 | static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) | 223 | static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) |
221 | { | 224 | { |
222 | __u32 s1,s2,d1,d2; | 225 | u32 s1, s2, d1, d2; |
223 | int direction = 2; | 226 | int direction = 2; |
224 | s1 = point(x1,y1); | 227 | s1 = point(x1, y1); |
225 | s2 = point(x1+w-1,y1+h-1); | 228 | s2 = point(x1 + w - 1, y1 + h - 1); |
226 | d1 = point(x2,y2); | 229 | d1 = point(x2, y2); |
227 | d2 = point(x2+w-1,y2+h-1); | 230 | d2 = point(x2 + w - 1, y2 + h - 1); |
228 | 231 | ||
229 | if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) | 232 | if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) |
230 | direction = 0; | 233 | direction = 0; |
231 | |||
232 | 234 | ||
233 | writemmr(ROP,ROP_S); | 235 | writemmr(ROP, ROP_S); |
234 | writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction); | 236 | writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); |
235 | 237 | ||
236 | writemmr(SR1,direction?s2:s1); | 238 | writemmr(SR1, direction ? s2 : s1); |
237 | writemmr(SR2,direction?s1:s2); | 239 | writemmr(SR2, direction ? s1 : s2); |
238 | writemmr(DR1,direction?d2:d1); | 240 | writemmr(DR1, direction ? d2 : d1); |
239 | writemmr(DR2,direction?d1:d2); | 241 | writemmr(DR2, direction ? d1 : d2); |
240 | } | 242 | } |
241 | 243 | ||
242 | static struct accel_switch accel_blade = { | 244 | static struct accel_switch accel_blade = { |
@@ -246,51 +248,72 @@ static struct accel_switch accel_blade = { | |||
246 | blade_copy_rect, | 248 | blade_copy_rect, |
247 | }; | 249 | }; |
248 | 250 | ||
249 | |||
250 | /* | 251 | /* |
251 | * BladeXP specific acceleration functions | 252 | * BladeXP specific acceleration functions |
252 | */ | 253 | */ |
253 | 254 | ||
254 | #define ROP_P 0xF0 | 255 | #define ROP_P 0xF0 |
255 | #define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff)) | 256 | #define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff)) |
256 | 257 | ||
257 | static void xp_init_accel(int pitch,int bpp) | 258 | static void xp_init_accel(int pitch, int bpp) |
258 | { | 259 | { |
259 | int tmp = 0,v1; | 260 | int tmp = 0, v1; |
260 | unsigned char x = 0; | 261 | unsigned char x = 0; |
261 | 262 | ||
262 | switch (bpp) { | 263 | switch (bpp) { |
263 | case 8: x = 0; break; | 264 | case 8: |
264 | case 16: x = 1; break; | 265 | x = 0; |
265 | case 24: x = 3; break; | 266 | break; |
266 | case 32: x = 2; break; | 267 | case 16: |
268 | x = 1; | ||
269 | break; | ||
270 | case 24: | ||
271 | x = 3; | ||
272 | break; | ||
273 | case 32: | ||
274 | x = 2; | ||
275 | break; | ||
267 | } | 276 | } |
268 | 277 | ||
269 | switch (pitch << (bpp >> 3)) { | 278 | switch (pitch << (bpp >> 3)) { |
270 | case 8192: | 279 | case 8192: |
271 | case 512: x |= 0x00; break; | 280 | case 512: |
272 | case 1024: x |= 0x04; break; | 281 | x |= 0x00; |
273 | case 2048: x |= 0x08; break; | 282 | break; |
274 | case 4096: x |= 0x0C; break; | 283 | case 1024: |
284 | x |= 0x04; | ||
285 | break; | ||
286 | case 2048: | ||
287 | x |= 0x08; | ||
288 | break; | ||
289 | case 4096: | ||
290 | x |= 0x0C; | ||
291 | break; | ||
275 | } | 292 | } |
276 | 293 | ||
277 | t_outb(x,0x2125); | 294 | t_outb(x, 0x2125); |
278 | 295 | ||
279 | eng_oper = x | 0x40; | 296 | eng_oper = x | 0x40; |
280 | 297 | ||
281 | switch (bpp) { | 298 | switch (bpp) { |
282 | case 8: tmp = 18; break; | 299 | case 8: |
283 | case 15: | 300 | tmp = 18; |
284 | case 16: tmp = 19; break; | 301 | break; |
285 | case 24: | 302 | case 15: |
286 | case 32: tmp = 20; break; | 303 | case 16: |
304 | tmp = 19; | ||
305 | break; | ||
306 | case 24: | ||
307 | case 32: | ||
308 | tmp = 20; | ||
309 | break; | ||
287 | } | 310 | } |
288 | 311 | ||
289 | v1 = pitch << tmp; | 312 | v1 = pitch << tmp; |
290 | 313 | ||
291 | writemmr(0x2154,v1); | 314 | writemmr(0x2154, v1); |
292 | writemmr(0x2150,v1); | 315 | writemmr(0x2150, v1); |
293 | t_outb(3,0x2126); | 316 | t_outb(3, 0x2126); |
294 | } | 317 | } |
295 | 318 | ||
296 | static void xp_wait_engine(void) | 319 | static void xp_wait_engine(void) |
@@ -318,24 +341,24 @@ static void xp_wait_engine(void) | |||
318 | } | 341 | } |
319 | } | 342 | } |
320 | 343 | ||
321 | static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) | 344 | static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) |
322 | { | 345 | { |
323 | writemmr(0x2127,ROP_P); | 346 | writemmr(0x2127, ROP_P); |
324 | writemmr(0x2158,c); | 347 | writemmr(0x2158, c); |
325 | writemmr(0x2128,0x4000); | 348 | writemmr(0x2128, 0x4000); |
326 | writemmr(0x2140,masked_point(h,w)); | 349 | writemmr(0x2140, masked_point(h, w)); |
327 | writemmr(0x2138,masked_point(y,x)); | 350 | writemmr(0x2138, masked_point(y, x)); |
328 | t_outb(0x01,0x2124); | 351 | t_outb(0x01, 0x2124); |
329 | t_outb(eng_oper,0x2125); | 352 | t_outb(eng_oper, 0x2125); |
330 | } | 353 | } |
331 | 354 | ||
332 | static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) | 355 | static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) |
333 | { | 356 | { |
334 | int direction; | 357 | int direction; |
335 | __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; | 358 | u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; |
336 | 359 | ||
337 | direction = 0x0004; | 360 | direction = 0x0004; |
338 | 361 | ||
339 | if ((x1 < x2) && (y1 == y2)) { | 362 | if ((x1 < x2) && (y1 == y2)) { |
340 | direction |= 0x0200; | 363 | direction |= 0x0200; |
341 | x1_tmp = x1 + w - 1; | 364 | x1_tmp = x1 + w - 1; |
@@ -344,53 +367,60 @@ static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) | |||
344 | x1_tmp = x1; | 367 | x1_tmp = x1; |
345 | x2_tmp = x2; | 368 | x2_tmp = x2; |
346 | } | 369 | } |
347 | 370 | ||
348 | if (y1 < y2) { | 371 | if (y1 < y2) { |
349 | direction |= 0x0100; | 372 | direction |= 0x0100; |
350 | y1_tmp = y1 + h - 1; | 373 | y1_tmp = y1 + h - 1; |
351 | y2_tmp = y2 + h - 1; | 374 | y2_tmp = y2 + h - 1; |
352 | } else { | 375 | } else { |
353 | y1_tmp = y1; | 376 | y1_tmp = y1; |
354 | y2_tmp = y2; | 377 | y2_tmp = y2; |
355 | } | 378 | } |
356 | 379 | ||
357 | writemmr(0x2128,direction); | 380 | writemmr(0x2128, direction); |
358 | t_outb(ROP_S,0x2127); | 381 | t_outb(ROP_S, 0x2127); |
359 | writemmr(0x213C,masked_point(y1_tmp,x1_tmp)); | 382 | writemmr(0x213C, masked_point(y1_tmp, x1_tmp)); |
360 | writemmr(0x2138,masked_point(y2_tmp,x2_tmp)); | 383 | writemmr(0x2138, masked_point(y2_tmp, x2_tmp)); |
361 | writemmr(0x2140,masked_point(h,w)); | 384 | writemmr(0x2140, masked_point(h, w)); |
362 | t_outb(0x01,0x2124); | 385 | t_outb(0x01, 0x2124); |
363 | } | 386 | } |
364 | 387 | ||
365 | static struct accel_switch accel_xp = { | 388 | static struct accel_switch accel_xp = { |
366 | xp_init_accel, | 389 | xp_init_accel, |
367 | xp_wait_engine, | 390 | xp_wait_engine, |
368 | xp_fill_rect, | 391 | xp_fill_rect, |
369 | xp_copy_rect, | 392 | xp_copy_rect, |
370 | }; | 393 | }; |
371 | 394 | ||
372 | |||
373 | /* | 395 | /* |
374 | * Image specific acceleration functions | 396 | * Image specific acceleration functions |
375 | */ | 397 | */ |
376 | static void image_init_accel(int pitch,int bpp) | 398 | static void image_init_accel(int pitch, int bpp) |
377 | { | 399 | { |
378 | int tmp = 0; | 400 | int tmp = 0; |
379 | switch (bpp) { | 401 | switch (bpp) { |
380 | case 8:tmp = 0;break; | 402 | case 8: |
381 | case 15:tmp = 5;break; | 403 | tmp = 0; |
382 | case 16:tmp = 1;break; | 404 | break; |
383 | case 24: | 405 | case 15: |
384 | case 32:tmp = 2;break; | 406 | tmp = 5; |
407 | break; | ||
408 | case 16: | ||
409 | tmp = 1; | ||
410 | break; | ||
411 | case 24: | ||
412 | case 32: | ||
413 | tmp = 2; | ||
414 | break; | ||
385 | } | 415 | } |
386 | writemmr(0x2120, 0xF0000000); | 416 | writemmr(0x2120, 0xF0000000); |
387 | writemmr(0x2120, 0x40000000|tmp); | 417 | writemmr(0x2120, 0x40000000 | tmp); |
388 | writemmr(0x2120, 0x80000000); | 418 | writemmr(0x2120, 0x80000000); |
389 | writemmr(0x2144, 0x00000000); | 419 | writemmr(0x2144, 0x00000000); |
390 | writemmr(0x2148, 0x00000000); | 420 | writemmr(0x2148, 0x00000000); |
391 | writemmr(0x2150, 0x00000000); | 421 | writemmr(0x2150, 0x00000000); |
392 | writemmr(0x2154, 0x00000000); | 422 | writemmr(0x2154, 0x00000000); |
393 | writemmr(0x2120, 0x60000000|(pitch<<16) |pitch); | 423 | writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch); |
394 | writemmr(0x216C, 0x00000000); | 424 | writemmr(0x216C, 0x00000000); |
395 | writemmr(0x2170, 0x00000000); | 425 | writemmr(0x2170, 0x00000000); |
396 | writemmr(0x217C, 0x00000000); | 426 | writemmr(0x217C, 0x00000000); |
@@ -400,44 +430,43 @@ static void image_init_accel(int pitch,int bpp) | |||
400 | 430 | ||
401 | static void image_wait_engine(void) | 431 | static void image_wait_engine(void) |
402 | { | 432 | { |
403 | while(readmmr(0x2164) & 0xF0000000); | 433 | while (readmmr(0x2164) & 0xF0000000) ; |
404 | } | 434 | } |
405 | 435 | ||
406 | static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop) | 436 | static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) |
407 | { | 437 | { |
408 | writemmr(0x2120,0x80000000); | 438 | writemmr(0x2120, 0x80000000); |
409 | writemmr(0x2120,0x90000000|ROP_S); | 439 | writemmr(0x2120, 0x90000000 | ROP_S); |
410 | 440 | ||
411 | writemmr(0x2144,c); | 441 | writemmr(0x2144, c); |
412 | 442 | ||
413 | writemmr(DR1,point(x,y)); | 443 | writemmr(DR1, point(x, y)); |
414 | writemmr(DR2,point(x+w-1,y+h-1)); | 444 | writemmr(DR2, point(x + w - 1, y + h - 1)); |
415 | 445 | ||
416 | writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9); | 446 | writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); |
417 | } | 447 | } |
418 | 448 | ||
419 | static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) | 449 | static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) |
420 | { | 450 | { |
421 | __u32 s1,s2,d1,d2; | 451 | u32 s1, s2, d1, d2; |
422 | int direction = 2; | 452 | int direction = 2; |
423 | s1 = point(x1,y1); | 453 | s1 = point(x1, y1); |
424 | s2 = point(x1+w-1,y1+h-1); | 454 | s2 = point(x1 + w - 1, y1 + h - 1); |
425 | d1 = point(x2,y2); | 455 | d1 = point(x2, y2); |
426 | d2 = point(x2+w-1,y2+h-1); | 456 | d2 = point(x2 + w - 1, y2 + h - 1); |
427 | |||
428 | if ((y1 > y2) || ((y1 == y2) && (x1 >x2))) | ||
429 | direction = 0; | ||
430 | |||
431 | writemmr(0x2120,0x80000000); | ||
432 | writemmr(0x2120,0x90000000|ROP_S); | ||
433 | |||
434 | writemmr(SR1,direction?s2:s1); | ||
435 | writemmr(SR2,direction?s1:s2); | ||
436 | writemmr(DR1,direction?d2:d1); | ||
437 | writemmr(DR2,direction?d1:d2); | ||
438 | writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction); | ||
439 | } | ||
440 | 457 | ||
458 | if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) | ||
459 | direction = 0; | ||
460 | |||
461 | writemmr(0x2120, 0x80000000); | ||
462 | writemmr(0x2120, 0x90000000 | ROP_S); | ||
463 | |||
464 | writemmr(SR1, direction ? s2 : s1); | ||
465 | writemmr(SR2, direction ? s1 : s2); | ||
466 | writemmr(DR1, direction ? d2 : d1); | ||
467 | writemmr(DR2, direction ? d1 : d2); | ||
468 | writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); | ||
469 | } | ||
441 | 470 | ||
442 | static struct accel_switch accel_image = { | 471 | static struct accel_switch accel_image = { |
443 | image_init_accel, | 472 | image_init_accel, |
@@ -450,30 +479,34 @@ static struct accel_switch accel_image = { | |||
450 | * Accel functions called by the upper layers | 479 | * Accel functions called by the upper layers |
451 | */ | 480 | */ |
452 | #ifdef CONFIG_FB_TRIDENT_ACCEL | 481 | #ifdef CONFIG_FB_TRIDENT_ACCEL |
453 | static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr) | 482 | static void tridentfb_fillrect(struct fb_info *info, |
483 | const struct fb_fillrect *fr) | ||
454 | { | 484 | { |
455 | int bpp = info->var.bits_per_pixel; | 485 | int bpp = info->var.bits_per_pixel; |
456 | int col = 0; | 486 | int col = 0; |
457 | 487 | ||
458 | switch (bpp) { | 488 | switch (bpp) { |
459 | default: | 489 | default: |
460 | case 8: col |= fr->color; | 490 | case 8: |
461 | col |= col << 8; | 491 | col |= fr->color; |
462 | col |= col << 16; | 492 | col |= col << 8; |
463 | break; | 493 | col |= col << 16; |
464 | case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; | 494 | break; |
465 | 495 | case 16: | |
466 | break; | 496 | col = ((u32 *)(info->pseudo_palette))[fr->color]; |
467 | case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; | 497 | break; |
468 | break; | 498 | case 32: |
469 | } | 499 | col = ((u32 *)(info->pseudo_palette))[fr->color]; |
470 | 500 | break; | |
501 | } | ||
502 | |||
471 | acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); | 503 | acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); |
472 | acc->wait_engine(); | 504 | acc->wait_engine(); |
473 | } | 505 | } |
474 | static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) | 506 | static void tridentfb_copyarea(struct fb_info *info, |
507 | const struct fb_copyarea *ca) | ||
475 | { | 508 | { |
476 | acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height); | 509 | acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height); |
477 | acc->wait_engine(); | 510 | acc->wait_engine(); |
478 | } | 511 | } |
479 | #else /* !CONFIG_FB_TRIDENT_ACCEL */ | 512 | #else /* !CONFIG_FB_TRIDENT_ACCEL */ |
@@ -488,14 +521,14 @@ static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *c | |||
488 | 521 | ||
489 | static inline unsigned char read3X4(int reg) | 522 | static inline unsigned char read3X4(int reg) |
490 | { | 523 | { |
491 | struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; | 524 | struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; |
492 | writeb(reg, par->io_virt + CRT + 4); | 525 | writeb(reg, par->io_virt + CRT + 4); |
493 | return readb( par->io_virt + CRT + 5); | 526 | return readb(par->io_virt + CRT + 5); |
494 | } | 527 | } |
495 | 528 | ||
496 | static inline void write3X4(int reg, unsigned char val) | 529 | static inline void write3X4(int reg, unsigned char val) |
497 | { | 530 | { |
498 | struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; | 531 | struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; |
499 | writeb(reg, par->io_virt + CRT + 4); | 532 | writeb(reg, par->io_virt + CRT + 4); |
500 | writeb(val, par->io_virt + CRT + 5); | 533 | writeb(val, par->io_virt + CRT + 5); |
501 | } | 534 | } |
@@ -520,7 +553,7 @@ static inline unsigned char read3CE(int reg) | |||
520 | 553 | ||
521 | static inline void writeAttr(int reg, unsigned char val) | 554 | static inline void writeAttr(int reg, unsigned char val) |
522 | { | 555 | { |
523 | readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index | 556 | readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */ |
524 | t_outb(reg, 0x3C0); | 557 | t_outb(reg, 0x3C0); |
525 | t_outb(val, 0x3C0); | 558 | t_outb(val, 0x3C0); |
526 | } | 559 | } |
@@ -540,32 +573,41 @@ static inline void enable_mmio(void) | |||
540 | /* Unprotect registers */ | 573 | /* Unprotect registers */ |
541 | outb(NewMode1, 0x3C4); | 574 | outb(NewMode1, 0x3C4); |
542 | outb(0x80, 0x3C5); | 575 | outb(0x80, 0x3C5); |
543 | 576 | ||
544 | /* Enable MMIO */ | 577 | /* Enable MMIO */ |
545 | outb(PCIReg, 0x3D4); | 578 | outb(PCIReg, 0x3D4); |
546 | outb(inb(0x3D5) | 0x01, 0x3D5); | 579 | outb(inb(0x3D5) | 0x01, 0x3D5); |
547 | } | 580 | } |
548 | 581 | ||
549 | |||
550 | #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) | 582 | #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) |
551 | 583 | ||
552 | /* Return flat panel's maximum x resolution */ | 584 | /* Return flat panel's maximum x resolution */ |
553 | static int __devinit get_nativex(void) | 585 | static int __devinit get_nativex(void) |
554 | { | 586 | { |
555 | int x,y,tmp; | 587 | int x, y, tmp; |
556 | 588 | ||
557 | if (nativex) | 589 | if (nativex) |
558 | return nativex; | 590 | return nativex; |
559 | 591 | ||
560 | tmp = (read3CE(VertStretch) >> 4) & 3; | 592 | tmp = (read3CE(VertStretch) >> 4) & 3; |
561 | 593 | ||
562 | switch (tmp) { | 594 | switch (tmp) { |
563 | case 0: x = 1280; y = 1024; break; | 595 | case 0: |
564 | case 2: x = 1024; y = 768; break; | 596 | x = 1280; y = 1024; |
565 | case 3: x = 800; y = 600; break; | 597 | break; |
566 | case 4: x = 1400; y = 1050; break; | 598 | case 2: |
567 | case 1: | 599 | x = 1024; y = 768; |
568 | default:x = 640; y = 480; break; | 600 | break; |
601 | case 3: | ||
602 | x = 800; y = 600; | ||
603 | break; | ||
604 | case 4: | ||
605 | x = 1400; y = 1050; | ||
606 | break; | ||
607 | case 1: | ||
608 | default: | ||
609 | x = 640; y = 480; | ||
610 | break; | ||
569 | } | 611 | } |
570 | 612 | ||
571 | output("%dx%d flat panel found\n", x, y); | 613 | output("%dx%d flat panel found\n", x, y); |
@@ -576,25 +618,26 @@ static int __devinit get_nativex(void) | |||
576 | static void set_lwidth(int width) | 618 | static void set_lwidth(int width) |
577 | { | 619 | { |
578 | write3X4(Offset, width & 0xFF); | 620 | write3X4(Offset, width & 0xFF); |
579 | write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4)); | 621 | write3X4(AddColReg, |
622 | (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4)); | ||
580 | } | 623 | } |
581 | 624 | ||
582 | /* For resolutions smaller than FP resolution stretch */ | 625 | /* For resolutions smaller than FP resolution stretch */ |
583 | static void screen_stretch(void) | 626 | static void screen_stretch(void) |
584 | { | 627 | { |
585 | if (chip_id != CYBERBLADEXPAi1) | 628 | if (chip_id != CYBERBLADEXPAi1) |
586 | write3CE(BiosReg,0); | 629 | write3CE(BiosReg, 0); |
587 | else | 630 | else |
588 | write3CE(BiosReg,8); | 631 | write3CE(BiosReg, 8); |
589 | write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1); | 632 | write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1); |
590 | write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1); | 633 | write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1); |
591 | } | 634 | } |
592 | 635 | ||
593 | /* For resolutions smaller than FP resolution center */ | 636 | /* For resolutions smaller than FP resolution center */ |
594 | static void screen_center(void) | 637 | static void screen_center(void) |
595 | { | 638 | { |
596 | write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80); | 639 | write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80); |
597 | write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80); | 640 | write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80); |
598 | } | 641 | } |
599 | 642 | ||
600 | /* Address of first shown pixel in display memory */ | 643 | /* Address of first shown pixel in display memory */ |
@@ -602,40 +645,42 @@ static void set_screen_start(int base) | |||
602 | { | 645 | { |
603 | write3X4(StartAddrLow, base & 0xFF); | 646 | write3X4(StartAddrLow, base & 0xFF); |
604 | write3X4(StartAddrHigh, (base & 0xFF00) >> 8); | 647 | write3X4(StartAddrHigh, (base & 0xFF00) >> 8); |
605 | write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); | 648 | write3X4(CRTCModuleTest, |
606 | write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); | 649 | (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); |
650 | write3X4(CRTHiOrd, | ||
651 | (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); | ||
607 | } | 652 | } |
608 | 653 | ||
609 | /* Use 20.12 fixed-point for NTSC value and frequency calculation */ | 654 | /* Use 20.12 fixed-point for NTSC value and frequency calculation */ |
610 | #define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 ) | 655 | #define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 ) |
611 | 656 | ||
612 | /* Set dotclock frequency */ | 657 | /* Set dotclock frequency */ |
613 | static void set_vclk(int freq) | 658 | static void set_vclk(int freq) |
614 | { | 659 | { |
615 | int m,n,k; | 660 | int m, n, k; |
616 | int f,fi,d,di; | 661 | int f, fi, d, di; |
617 | unsigned char lo=0,hi=0; | 662 | unsigned char lo = 0, hi = 0; |
618 | 663 | ||
619 | d = 20; | 664 | d = 20; |
620 | for(k = 2;k>=0;k--) | 665 | for (k = 2; k >= 0; k--) |
621 | for(m = 0;m<63;m++) | 666 | for (m = 0; m < 63; m++) |
622 | for(n = 0;n<128;n++) { | 667 | for (n = 0; n < 128; n++) { |
623 | fi = calc_freq(n,m,k); | 668 | fi = calc_freq(n, m, k); |
624 | if ((di = abs(fi - freq)) < d) { | 669 | if ((di = abs(fi - freq)) < d) { |
625 | d = di; | 670 | d = di; |
626 | f = fi; | 671 | f = fi; |
627 | lo = n; | 672 | lo = n; |
628 | hi = (k<<6) | m; | 673 | hi = (k << 6) | m; |
629 | } | 674 | } |
630 | } | 675 | } |
631 | if (chip3D) { | 676 | if (chip3D) { |
632 | write3C4(ClockHigh,hi); | 677 | write3C4(ClockHigh, hi); |
633 | write3C4(ClockLow,lo); | 678 | write3C4(ClockLow, lo); |
634 | } else { | 679 | } else { |
635 | outb(lo,0x43C8); | 680 | outb(lo, 0x43C8); |
636 | outb(hi,0x43C9); | 681 | outb(hi, 0x43C9); |
637 | } | 682 | } |
638 | debug("VCLK = %X %X\n",hi,lo); | 683 | debug("VCLK = %X %X\n", hi, lo); |
639 | } | 684 | } |
640 | 685 | ||
641 | /* Set number of lines for flat panels*/ | 686 | /* Set number of lines for flat panels*/ |
@@ -663,7 +708,7 @@ static unsigned int __devinit get_displaytype(void) | |||
663 | return DISPLAY_FP; | 708 | return DISPLAY_FP; |
664 | if (crt || !chipcyber) | 709 | if (crt || !chipcyber) |
665 | return DISPLAY_CRT; | 710 | return DISPLAY_CRT; |
666 | return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT; | 711 | return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; |
667 | } | 712 | } |
668 | 713 | ||
669 | /* Try detecting the video memory size */ | 714 | /* Try detecting the video memory size */ |
@@ -676,100 +721,136 @@ static unsigned int __devinit get_memsize(void) | |||
676 | if (memsize) | 721 | if (memsize) |
677 | k = memsize * Kb; | 722 | k = memsize * Kb; |
678 | else | 723 | else |
679 | switch (chip_id) { | 724 | switch (chip_id) { |
680 | case CYBER9525DVD: k = 2560 * Kb; break; | 725 | case CYBER9525DVD: |
726 | k = 2560 * Kb; | ||
727 | break; | ||
681 | default: | 728 | default: |
682 | tmp = read3X4(SPR) & 0x0F; | 729 | tmp = read3X4(SPR) & 0x0F; |
683 | switch (tmp) { | 730 | switch (tmp) { |
684 | 731 | ||
685 | case 0x01: k = 512; break; | 732 | case 0x01: |
686 | case 0x02: k = 6 * Mb; break; /* XP */ | 733 | k = 512; |
687 | case 0x03: k = 1 * Mb; break; | 734 | break; |
688 | case 0x04: k = 8 * Mb; break; | 735 | case 0x02: |
689 | case 0x06: k = 10 * Mb; break; /* XP */ | 736 | k = 6 * Mb; /* XP */ |
690 | case 0x07: k = 2 * Mb; break; | 737 | break; |
691 | case 0x08: k = 12 * Mb; break; /* XP */ | 738 | case 0x03: |
692 | case 0x0A: k = 14 * Mb; break; /* XP */ | 739 | k = 1 * Mb; |
693 | case 0x0C: k = 16 * Mb; break; /* XP */ | 740 | break; |
694 | case 0x0E: /* XP */ | 741 | case 0x04: |
695 | 742 | k = 8 * Mb; | |
696 | tmp2 = read3C4(0xC1); | 743 | break; |
697 | switch (tmp2) { | 744 | case 0x06: |
698 | case 0x00: k = 20 * Mb; break; | 745 | k = 10 * Mb; /* XP */ |
699 | case 0x01: k = 24 * Mb; break; | 746 | break; |
700 | case 0x10: k = 28 * Mb; break; | 747 | case 0x07: |
701 | case 0x11: k = 32 * Mb; break; | 748 | k = 2 * Mb; |
702 | default: k = 1 * Mb; break; | 749 | break; |
703 | } | 750 | case 0x08: |
751 | k = 12 * Mb; /* XP */ | ||
752 | break; | ||
753 | case 0x0A: | ||
754 | k = 14 * Mb; /* XP */ | ||
755 | break; | ||
756 | case 0x0C: | ||
757 | k = 16 * Mb; /* XP */ | ||
758 | break; | ||
759 | case 0x0E: /* XP */ | ||
760 | |||
761 | tmp2 = read3C4(0xC1); | ||
762 | switch (tmp2) { | ||
763 | case 0x00: | ||
764 | k = 20 * Mb; | ||
765 | break; | ||
766 | case 0x01: | ||
767 | k = 24 * Mb; | ||
768 | break; | ||
769 | case 0x10: | ||
770 | k = 28 * Mb; | ||
771 | break; | ||
772 | case 0x11: | ||
773 | k = 32 * Mb; | ||
774 | break; | ||
775 | default: | ||
776 | k = 1 * Mb; | ||
777 | break; | ||
778 | } | ||
779 | break; | ||
780 | |||
781 | case 0x0F: | ||
782 | k = 4 * Mb; | ||
783 | break; | ||
784 | default: | ||
785 | k = 1 * Mb; | ||
704 | break; | 786 | break; |
705 | |||
706 | case 0x0F: k = 4 * Mb; break; | ||
707 | default: k = 1 * Mb; | ||
708 | } | 787 | } |
709 | } | 788 | } |
710 | 789 | ||
711 | k -= memdiff * Kb; | 790 | k -= memdiff * Kb; |
712 | output("framebuffer size = %d Kb\n", k/Kb); | 791 | output("framebuffer size = %d Kb\n", k / Kb); |
713 | return k; | 792 | return k; |
714 | } | 793 | } |
715 | 794 | ||
716 | /* See if we can handle the video mode described in var */ | 795 | /* See if we can handle the video mode described in var */ |
717 | static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 796 | static int tridentfb_check_var(struct fb_var_screeninfo *var, |
797 | struct fb_info *info) | ||
718 | { | 798 | { |
719 | int bpp = var->bits_per_pixel; | 799 | int bpp = var->bits_per_pixel; |
720 | debug("enter\n"); | 800 | debug("enter\n"); |
721 | 801 | ||
722 | /* check color depth */ | 802 | /* check color depth */ |
723 | if (bpp == 24 ) | 803 | if (bpp == 24) |
724 | bpp = var->bits_per_pixel = 32; | 804 | bpp = var->bits_per_pixel = 32; |
725 | /* check whether resolution fits on panel and in memory*/ | 805 | /* check whether resolution fits on panel and in memory */ |
726 | if (flatpanel && nativex && var->xres > nativex) | 806 | if (flatpanel && nativex && var->xres > nativex) |
727 | return -EINVAL; | 807 | return -EINVAL; |
728 | if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len) | 808 | if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len) |
729 | return -EINVAL; | 809 | return -EINVAL; |
730 | 810 | ||
731 | switch (bpp) { | 811 | switch (bpp) { |
732 | case 8: | 812 | case 8: |
733 | var->red.offset = 0; | 813 | var->red.offset = 0; |
734 | var->green.offset = 0; | 814 | var->green.offset = 0; |
735 | var->blue.offset = 0; | 815 | var->blue.offset = 0; |
736 | var->red.length = 6; | 816 | var->red.length = 6; |
737 | var->green.length = 6; | 817 | var->green.length = 6; |
738 | var->blue.length = 6; | 818 | var->blue.length = 6; |
739 | break; | 819 | break; |
740 | case 16: | 820 | case 16: |
741 | var->red.offset = 11; | 821 | var->red.offset = 11; |
742 | var->green.offset = 5; | 822 | var->green.offset = 5; |
743 | var->blue.offset = 0; | 823 | var->blue.offset = 0; |
744 | var->red.length = 5; | 824 | var->red.length = 5; |
745 | var->green.length = 6; | 825 | var->green.length = 6; |
746 | var->blue.length = 5; | 826 | var->blue.length = 5; |
747 | break; | 827 | break; |
748 | case 32: | 828 | case 32: |
749 | var->red.offset = 16; | 829 | var->red.offset = 16; |
750 | var->green.offset = 8; | 830 | var->green.offset = 8; |
751 | var->blue.offset = 0; | 831 | var->blue.offset = 0; |
752 | var->red.length = 8; | 832 | var->red.length = 8; |
753 | var->green.length = 8; | 833 | var->green.length = 8; |
754 | var->blue.length = 8; | 834 | var->blue.length = 8; |
755 | break; | 835 | break; |
756 | default: | 836 | default: |
757 | return -EINVAL; | 837 | return -EINVAL; |
758 | } | 838 | } |
759 | debug("exit\n"); | 839 | debug("exit\n"); |
760 | 840 | ||
761 | return 0; | 841 | return 0; |
762 | 842 | ||
763 | } | 843 | } |
844 | |||
764 | /* Pan the display */ | 845 | /* Pan the display */ |
765 | static int tridentfb_pan_display(struct fb_var_screeninfo *var, | 846 | static int tridentfb_pan_display(struct fb_var_screeninfo *var, |
766 | struct fb_info *info) | 847 | struct fb_info *info) |
767 | { | 848 | { |
768 | unsigned int offset; | 849 | unsigned int offset; |
769 | 850 | ||
770 | debug("enter\n"); | 851 | debug("enter\n"); |
771 | offset = (var->xoffset + (var->yoffset * var->xres)) | 852 | offset = (var->xoffset + (var->yoffset * var->xres)) |
772 | * var->bits_per_pixel/32; | 853 | * var->bits_per_pixel / 32; |
773 | info->var.xoffset = var->xoffset; | 854 | info->var.xoffset = var->xoffset; |
774 | info->var.yoffset = var->yoffset; | 855 | info->var.yoffset = var->yoffset; |
775 | set_screen_start(offset); | 856 | set_screen_start(offset); |
@@ -777,36 +858,38 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var, | |||
777 | return 0; | 858 | return 0; |
778 | } | 859 | } |
779 | 860 | ||
780 | #define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81) | 861 | #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81) |
781 | #define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E) | 862 | #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E) |
782 | 863 | ||
783 | /* Set the hardware to the requested video mode */ | 864 | /* Set the hardware to the requested video mode */ |
784 | static int tridentfb_set_par(struct fb_info *info) | 865 | static int tridentfb_set_par(struct fb_info *info) |
785 | { | 866 | { |
786 | struct tridentfb_par * par = (struct tridentfb_par *)(info->par); | 867 | struct tridentfb_par *par = (struct tridentfb_par *)(info->par); |
787 | u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend, | 868 | u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; |
788 | vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend; | 869 | u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; |
789 | struct fb_var_screeninfo *var = &info->var; | 870 | struct fb_var_screeninfo *var = &info->var; |
790 | int bpp = var->bits_per_pixel; | 871 | int bpp = var->bits_per_pixel; |
791 | unsigned char tmp; | 872 | unsigned char tmp; |
792 | debug("enter\n"); | 873 | debug("enter\n"); |
793 | htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10; | 874 | hdispend = var->xres / 8 - 1; |
794 | hdispend = var->xres/8 - 1; | 875 | hsyncstart = (var->xres + var->right_margin) / 8; |
795 | hsyncstart = (var->xres + var->right_margin)/8; | 876 | hsyncend = var->hsync_len / 8; |
796 | hsyncend = var->hsync_len/8; | 877 | htotal = |
878 | (var->xres + var->left_margin + var->right_margin + | ||
879 | var->hsync_len) / 8 - 10; | ||
797 | hblankstart = hdispend + 1; | 880 | hblankstart = hdispend + 1; |
798 | hblankend = htotal + 5; | 881 | hblankend = htotal + 5; |
799 | 882 | ||
800 | vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2; | ||
801 | vdispend = var->yres - 1; | 883 | vdispend = var->yres - 1; |
802 | vsyncstart = var->yres + var->lower_margin; | 884 | vsyncstart = var->yres + var->lower_margin; |
803 | vsyncend = var->vsync_len; | 885 | vsyncend = var->vsync_len; |
886 | vtotal = var->upper_margin + vsyncstart + vsyncend - 2; | ||
804 | vblankstart = var->yres; | 887 | vblankstart = var->yres; |
805 | vblankend = vtotal + 2; | 888 | vblankend = vtotal + 2; |
806 | 889 | ||
807 | enable_mmio(); | 890 | enable_mmio(); |
808 | crtc_unlock(); | 891 | crtc_unlock(); |
809 | write3CE(CyberControl,8); | 892 | write3CE(CyberControl, 8); |
810 | 893 | ||
811 | if (flatpanel && var->xres < nativex) { | 894 | if (flatpanel && var->xres < nativex) { |
812 | /* | 895 | /* |
@@ -814,18 +897,18 @@ static int tridentfb_set_par(struct fb_info *info) | |||
814 | * than requested resolution decide whether | 897 | * than requested resolution decide whether |
815 | * we stretch or center | 898 | * we stretch or center |
816 | */ | 899 | */ |
817 | t_outb(0xEB,0x3C2); | 900 | t_outb(0xEB, 0x3C2); |
818 | 901 | ||
819 | shadowmode_on(); | 902 | shadowmode_on(); |
820 | 903 | ||
821 | if (center) | 904 | if (center) |
822 | screen_center(); | 905 | screen_center(); |
823 | else if (stretch) | 906 | else if (stretch) |
824 | screen_stretch(); | 907 | screen_stretch(); |
825 | 908 | ||
826 | } else { | 909 | } else { |
827 | t_outb(0x2B,0x3C2); | 910 | t_outb(0x2B, 0x3C2); |
828 | write3CE(CyberControl,8); | 911 | write3CE(CyberControl, 8); |
829 | } | 912 | } |
830 | 913 | ||
831 | /* vertical timing values */ | 914 | /* vertical timing values */ |
@@ -834,15 +917,15 @@ static int tridentfb_set_par(struct fb_info *info) | |||
834 | write3X4(CRTVSyncStart, vsyncstart & 0xFF); | 917 | write3X4(CRTVSyncStart, vsyncstart & 0xFF); |
835 | write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); | 918 | write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); |
836 | write3X4(CRTVBlankStart, vblankstart & 0xFF); | 919 | write3X4(CRTVBlankStart, vblankstart & 0xFF); |
837 | write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/); | 920 | write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ ); |
838 | 921 | ||
839 | /* horizontal timing values */ | 922 | /* horizontal timing values */ |
840 | write3X4(CRTHTotal, htotal & 0xFF); | 923 | write3X4(CRTHTotal, htotal & 0xFF); |
841 | write3X4(CRTHDispEnd, hdispend & 0xFF); | 924 | write3X4(CRTHDispEnd, hdispend & 0xFF); |
842 | write3X4(CRTHSyncStart, hsyncstart & 0xFF); | 925 | write3X4(CRTHSyncStart, hsyncstart & 0xFF); |
843 | write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2)); | 926 | write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); |
844 | write3X4(CRTHBlankStart, hblankstart & 0xFF); | 927 | write3X4(CRTHBlankStart, hblankstart & 0xFF); |
845 | write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/); | 928 | write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ ); |
846 | 929 | ||
847 | /* higher bits of vertical timing values */ | 930 | /* higher bits of vertical timing values */ |
848 | tmp = 0x10; | 931 | tmp = 0x10; |
@@ -856,7 +939,7 @@ static int tridentfb_set_par(struct fb_info *info) | |||
856 | if (vsyncstart & 0x200) tmp |= 0x80; | 939 | if (vsyncstart & 0x200) tmp |= 0x80; |
857 | write3X4(CRTOverflow, tmp); | 940 | write3X4(CRTOverflow, tmp); |
858 | 941 | ||
859 | tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10 | 942 | tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */ |
860 | if (vtotal & 0x400) tmp |= 0x80; | 943 | if (vtotal & 0x400) tmp |= 0x80; |
861 | if (vblankstart & 0x400) tmp |= 0x40; | 944 | if (vblankstart & 0x400) tmp |= 0x40; |
862 | if (vsyncstart & 0x400) tmp |= 0x20; | 945 | if (vsyncstart & 0x400) tmp |= 0x20; |
@@ -867,84 +950,100 @@ static int tridentfb_set_par(struct fb_info *info) | |||
867 | if (htotal & 0x800) tmp |= 0x800 >> 11; | 950 | if (htotal & 0x800) tmp |= 0x800 >> 11; |
868 | if (hblankstart & 0x800) tmp |= 0x800 >> 7; | 951 | if (hblankstart & 0x800) tmp |= 0x800 >> 7; |
869 | write3X4(HorizOverflow, tmp); | 952 | write3X4(HorizOverflow, tmp); |
870 | 953 | ||
871 | tmp = 0x40; | 954 | tmp = 0x40; |
872 | if (vblankstart & 0x200) tmp |= 0x20; | 955 | if (vblankstart & 0x200) tmp |= 0x20; |
873 | //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes | 956 | //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */ |
874 | write3X4(CRTMaxScanLine, tmp); | 957 | write3X4(CRTMaxScanLine, tmp); |
875 | 958 | ||
876 | write3X4(CRTLineCompare,0xFF); | 959 | write3X4(CRTLineCompare, 0xFF); |
877 | write3X4(CRTPRowScan,0); | 960 | write3X4(CRTPRowScan, 0); |
878 | write3X4(CRTModeControl,0xC3); | 961 | write3X4(CRTModeControl, 0xC3); |
879 | 962 | ||
880 | write3X4(LinearAddReg,0x20); //enable linear addressing | 963 | write3X4(LinearAddReg, 0x20); /* enable linear addressing */ |
881 | 964 | ||
882 | tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80; | 965 | tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80; |
883 | write3X4(CRTCModuleTest,tmp); //enable access extended memory | 966 | write3X4(CRTCModuleTest, tmp); /* enable access extended memory */ |
884 | 967 | ||
885 | write3X4(GraphEngReg, 0x80); //enable GE for text acceleration | 968 | write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */ |
886 | 969 | ||
887 | #ifdef CONFIG_FB_TRIDENT_ACCEL | 970 | #ifdef CONFIG_FB_TRIDENT_ACCEL |
888 | acc->init_accel(info->var.xres,bpp); | 971 | acc->init_accel(info->var.xres, bpp); |
889 | #endif | 972 | #endif |
890 | 973 | ||
891 | switch (bpp) { | 974 | switch (bpp) { |
892 | case 8: tmp = 0x00; break; | 975 | case 8: |
893 | case 16: tmp = 0x05; break; | 976 | tmp = 0x00; |
894 | case 24: tmp = 0x29; break; | 977 | break; |
895 | case 32: tmp = 0x09; | 978 | case 16: |
979 | tmp = 0x05; | ||
980 | break; | ||
981 | case 24: | ||
982 | tmp = 0x29; | ||
983 | break; | ||
984 | case 32: | ||
985 | tmp = 0x09; | ||
986 | break; | ||
896 | } | 987 | } |
897 | 988 | ||
898 | write3X4(PixelBusReg, tmp); | 989 | write3X4(PixelBusReg, tmp); |
899 | 990 | ||
900 | tmp = 0x10; | 991 | tmp = 0x10; |
901 | if (chipcyber) | 992 | if (chipcyber) |
902 | tmp |= 0x20; | 993 | tmp |= 0x20; |
903 | write3X4(DRAMControl, tmp); //both IO,linear enable | 994 | write3X4(DRAMControl, tmp); /* both IO, linear enable */ |
904 | 995 | ||
905 | write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40); | 996 | write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40); |
906 | write3X4(Performance,0x92); | 997 | write3X4(Performance, 0x92); |
907 | write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable | 998 | write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */ |
908 | 999 | ||
909 | /* convert from picoseconds to MHz */ | 1000 | /* convert from picoseconds to MHz */ |
910 | par->vclk = 1000000/info->var.pixclock; | 1001 | par->vclk = 1000000 / info->var.pixclock; |
911 | if (bpp == 32) | 1002 | if (bpp == 32) |
912 | par->vclk *=2; | 1003 | par->vclk *= 2; |
913 | set_vclk(par->vclk); | 1004 | set_vclk(par->vclk); |
914 | 1005 | ||
915 | write3C4(0,3); | 1006 | write3C4(0, 3); |
916 | write3C4(1,1); //set char clock 8 dots wide | 1007 | write3C4(1, 1); /* set char clock 8 dots wide */ |
917 | write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode | 1008 | write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */ |
918 | write3C4(3,0); | 1009 | write3C4(3, 0); |
919 | write3C4(4,0x0E); //memory mode enable bitmaps ?? | 1010 | write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */ |
920 | 1011 | ||
921 | write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp | 1012 | write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */ |
922 | //chain4 mode display and CPU path | 1013 | /* chain4 mode display and CPU path */ |
923 | write3CE(0x5,0x40); //no CGA compat,allow 256 col | 1014 | write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */ |
924 | write3CE(0x6,0x05); //graphics mode | 1015 | write3CE(0x6, 0x05); /* graphics mode */ |
925 | write3CE(0x7,0x0F); //planes? | 1016 | write3CE(0x7, 0x0F); /* planes? */ |
926 | 1017 | ||
927 | if (chip_id == CYBERBLADEXPAi1) { | 1018 | if (chip_id == CYBERBLADEXPAi1) { |
928 | /* This fixes snow-effect in 32 bpp */ | 1019 | /* This fixes snow-effect in 32 bpp */ |
929 | write3X4(CRTHSyncStart,0x84); | 1020 | write3X4(CRTHSyncStart, 0x84); |
930 | } | 1021 | } |
931 | 1022 | ||
932 | writeAttr(0x10,0x41); //graphics mode and support 256 color modes | 1023 | writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */ |
933 | writeAttr(0x12,0x0F); //planes | 1024 | writeAttr(0x12, 0x0F); /* planes */ |
934 | writeAttr(0x13,0); //horizontal pel panning | 1025 | writeAttr(0x13, 0); /* horizontal pel panning */ |
935 | 1026 | ||
936 | //colors | 1027 | /* colors */ |
937 | for(tmp = 0;tmp < 0x10;tmp++) | 1028 | for (tmp = 0; tmp < 0x10; tmp++) |
938 | writeAttr(tmp,tmp); | 1029 | writeAttr(tmp, tmp); |
939 | readb(par->io_virt + CRT + 0x0A); //flip-flop to index | 1030 | readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */ |
940 | t_outb(0x20, 0x3C0); //enable attr | 1031 | t_outb(0x20, 0x3C0); /* enable attr */ |
941 | 1032 | ||
942 | switch (bpp) { | 1033 | switch (bpp) { |
943 | case 8: tmp = 0;break; //256 colors | 1034 | case 8: |
944 | case 15: tmp = 0x10;break; | 1035 | tmp = 0; |
945 | case 16: tmp = 0x30;break; //hicolor | 1036 | break; |
946 | case 24: //truecolor | 1037 | case 15: |
947 | case 32: tmp = 0xD0;break; | 1038 | tmp = 0x10; |
1039 | break; | ||
1040 | case 16: | ||
1041 | tmp = 0x30; | ||
1042 | break; | ||
1043 | case 24: | ||
1044 | case 32: | ||
1045 | tmp = 0xD0; | ||
1046 | break; | ||
948 | } | 1047 | } |
949 | 1048 | ||
950 | t_inb(0x3C8); | 1049 | t_inb(0x3C8); |
@@ -952,37 +1051,36 @@ static int tridentfb_set_par(struct fb_info *info) | |||
952 | t_inb(0x3C6); | 1051 | t_inb(0x3C6); |
953 | t_inb(0x3C6); | 1052 | t_inb(0x3C6); |
954 | t_inb(0x3C6); | 1053 | t_inb(0x3C6); |
955 | t_outb(tmp,0x3C6); | 1054 | t_outb(tmp, 0x3C6); |
956 | t_inb(0x3C8); | 1055 | t_inb(0x3C8); |
957 | 1056 | ||
958 | if (flatpanel) | 1057 | if (flatpanel) |
959 | set_number_of_lines(info->var.yres); | 1058 | set_number_of_lines(info->var.yres); |
960 | set_lwidth(info->var.xres * bpp/(4*16)); | 1059 | set_lwidth(info->var.xres * bpp / (4 * 16)); |
961 | info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | 1060 | info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
962 | info->fix.line_length = info->var.xres * (bpp >> 3); | 1061 | info->fix.line_length = info->var.xres * (bpp >> 3); |
963 | info->cmap.len = (bpp == 8) ? 256: 16; | 1062 | info->cmap.len = (bpp == 8) ? 256 : 16; |
964 | debug("exit\n"); | 1063 | debug("exit\n"); |
965 | return 0; | 1064 | return 0; |
966 | } | 1065 | } |
967 | 1066 | ||
968 | /* Set one color register */ | 1067 | /* Set one color register */ |
969 | static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | 1068 | static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
970 | unsigned blue, unsigned transp, | 1069 | unsigned blue, unsigned transp, |
971 | struct fb_info *info) | 1070 | struct fb_info *info) |
972 | { | 1071 | { |
973 | int bpp = info->var.bits_per_pixel; | 1072 | int bpp = info->var.bits_per_pixel; |
974 | 1073 | ||
975 | if (regno >= info->cmap.len) | 1074 | if (regno >= info->cmap.len) |
976 | return 1; | 1075 | return 1; |
977 | 1076 | ||
978 | |||
979 | if (bpp == 8) { | 1077 | if (bpp == 8) { |
980 | t_outb(0xFF,0x3C6); | 1078 | t_outb(0xFF, 0x3C6); |
981 | t_outb(regno,0x3C8); | 1079 | t_outb(regno, 0x3C8); |
982 | 1080 | ||
983 | t_outb(red>>10,0x3C9); | 1081 | t_outb(red >> 10, 0x3C9); |
984 | t_outb(green>>10,0x3C9); | 1082 | t_outb(green >> 10, 0x3C9); |
985 | t_outb(blue>>10,0x3C9); | 1083 | t_outb(blue >> 10, 0x3C9); |
986 | 1084 | ||
987 | } else if (regno < 16) { | 1085 | } else if (regno < 16) { |
988 | if (bpp == 16) { /* RGB 565 */ | 1086 | if (bpp == 16) { /* RGB 565 */ |
@@ -994,29 +1092,28 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
994 | ((u32 *)(info->pseudo_palette))[regno] = col; | 1092 | ((u32 *)(info->pseudo_palette))[regno] = col; |
995 | } else if (bpp == 32) /* ARGB 8888 */ | 1093 | } else if (bpp == 32) /* ARGB 8888 */ |
996 | ((u32*)info->pseudo_palette)[regno] = | 1094 | ((u32*)info->pseudo_palette)[regno] = |
997 | ((transp & 0xFF00) <<16) | | 1095 | ((transp & 0xFF00) << 16) | |
998 | ((red & 0xFF00) << 8) | | 1096 | ((red & 0xFF00) << 8) | |
999 | ((green & 0xFF00)) | | 1097 | ((green & 0xFF00)) | |
1000 | ((blue & 0xFF00)>>8); | 1098 | ((blue & 0xFF00) >> 8); |
1001 | } | 1099 | } |
1002 | 1100 | ||
1003 | // debug("exit\n"); | 1101 | /* debug("exit\n"); */ |
1004 | return 0; | 1102 | return 0; |
1005 | } | 1103 | } |
1006 | 1104 | ||
1007 | /* Try blanking the screen.For flat panels it does nothing */ | 1105 | /* Try blanking the screen.For flat panels it does nothing */ |
1008 | static int tridentfb_blank(int blank_mode, struct fb_info *info) | 1106 | static int tridentfb_blank(int blank_mode, struct fb_info *info) |
1009 | { | 1107 | { |
1010 | unsigned char PMCont,DPMSCont; | 1108 | unsigned char PMCont, DPMSCont; |
1011 | 1109 | ||
1012 | debug("enter\n"); | 1110 | debug("enter\n"); |
1013 | if (flatpanel) | 1111 | if (flatpanel) |
1014 | return 0; | 1112 | return 0; |
1015 | t_outb(0x04,0x83C8); /* Read DPMS Control */ | 1113 | t_outb(0x04, 0x83C8); /* Read DPMS Control */ |
1016 | PMCont = t_inb(0x83C6) & 0xFC; | 1114 | PMCont = t_inb(0x83C6) & 0xFC; |
1017 | DPMSCont = read3CE(PowerStatus) & 0xFC; | 1115 | DPMSCont = read3CE(PowerStatus) & 0xFC; |
1018 | switch (blank_mode) | 1116 | switch (blank_mode) { |
1019 | { | ||
1020 | case FB_BLANK_UNBLANK: | 1117 | case FB_BLANK_UNBLANK: |
1021 | /* Screen: On, HSync: On, VSync: On */ | 1118 | /* Screen: On, HSync: On, VSync: On */ |
1022 | case FB_BLANK_NORMAL: | 1119 | case FB_BLANK_NORMAL: |
@@ -1039,11 +1136,11 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info) | |||
1039 | PMCont |= 0x00; | 1136 | PMCont |= 0x00; |
1040 | DPMSCont |= 0x03; | 1137 | DPMSCont |= 0x03; |
1041 | break; | 1138 | break; |
1042 | } | 1139 | } |
1043 | 1140 | ||
1044 | write3CE(PowerStatus,DPMSCont); | 1141 | write3CE(PowerStatus, DPMSCont); |
1045 | t_outb(4,0x83C8); | 1142 | t_outb(4, 0x83C8); |
1046 | t_outb(PMCont,0x83C6); | 1143 | t_outb(PMCont, 0x83C6); |
1047 | 1144 | ||
1048 | debug("exit\n"); | 1145 | debug("exit\n"); |
1049 | 1146 | ||
@@ -1051,7 +1148,20 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info) | |||
1051 | return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; | 1148 | return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; |
1052 | } | 1149 | } |
1053 | 1150 | ||
1054 | static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id) | 1151 | static struct fb_ops tridentfb_ops = { |
1152 | .owner = THIS_MODULE, | ||
1153 | .fb_setcolreg = tridentfb_setcolreg, | ||
1154 | .fb_pan_display = tridentfb_pan_display, | ||
1155 | .fb_blank = tridentfb_blank, | ||
1156 | .fb_check_var = tridentfb_check_var, | ||
1157 | .fb_set_par = tridentfb_set_par, | ||
1158 | .fb_fillrect = tridentfb_fillrect, | ||
1159 | .fb_copyarea = tridentfb_copyarea, | ||
1160 | .fb_imageblit = cfb_imageblit, | ||
1161 | }; | ||
1162 | |||
1163 | static int __devinit trident_pci_probe(struct pci_dev * dev, | ||
1164 | const struct pci_device_id * id) | ||
1055 | { | 1165 | { |
1056 | int err; | 1166 | int err; |
1057 | unsigned char revision; | 1167 | unsigned char revision; |
@@ -1062,31 +1172,42 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1062 | 1172 | ||
1063 | chip_id = id->device; | 1173 | chip_id = id->device; |
1064 | 1174 | ||
1065 | if(chip_id == CYBERBLADEi1) | 1175 | if (chip_id == CYBERBLADEi1) |
1066 | output("*** Please do use cyblafb, Cyberblade/i1 support " | 1176 | output("*** Please do use cyblafb, Cyberblade/i1 support " |
1067 | "will soon be removed from tridentfb!\n"); | 1177 | "will soon be removed from tridentfb!\n"); |
1068 | 1178 | ||
1069 | 1179 | ||
1070 | /* If PCI id is 0x9660 then further detect chip type */ | 1180 | /* If PCI id is 0x9660 then further detect chip type */ |
1071 | 1181 | ||
1072 | if (chip_id == TGUI9660) { | 1182 | if (chip_id == TGUI9660) { |
1073 | outb(RevisionID,0x3C4); | 1183 | outb(RevisionID, 0x3C4); |
1074 | revision = inb(0x3C5); | 1184 | revision = inb(0x3C5); |
1075 | 1185 | ||
1076 | switch (revision) { | 1186 | switch (revision) { |
1077 | case 0x22: | 1187 | case 0x22: |
1078 | case 0x23: chip_id = CYBER9397;break; | 1188 | case 0x23: |
1079 | case 0x2A: chip_id = CYBER9397DVD;break; | 1189 | chip_id = CYBER9397; |
1080 | case 0x30: | 1190 | break; |
1081 | case 0x33: | 1191 | case 0x2A: |
1082 | case 0x34: | 1192 | chip_id = CYBER9397DVD; |
1083 | case 0x35: | 1193 | break; |
1084 | case 0x38: | 1194 | case 0x30: |
1085 | case 0x3A: | 1195 | case 0x33: |
1086 | case 0xB3: chip_id = CYBER9385;break; | 1196 | case 0x34: |
1087 | case 0x40 ... 0x43: chip_id = CYBER9382;break; | 1197 | case 0x35: |
1088 | case 0x4A: chip_id = CYBER9388;break; | 1198 | case 0x38: |
1089 | default:break; | 1199 | case 0x3A: |
1200 | case 0xB3: | ||
1201 | chip_id = CYBER9385; | ||
1202 | break; | ||
1203 | case 0x40 ... 0x43: | ||
1204 | chip_id = CYBER9382; | ||
1205 | break; | ||
1206 | case 0x4A: | ||
1207 | chip_id = CYBER9388; | ||
1208 | break; | ||
1209 | default: | ||
1210 | break; | ||
1090 | } | 1211 | } |
1091 | } | 1212 | } |
1092 | 1213 | ||
@@ -1095,8 +1216,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1095 | 1216 | ||
1096 | if (is_xp(chip_id)) { | 1217 | if (is_xp(chip_id)) { |
1097 | acc = &accel_xp; | 1218 | acc = &accel_xp; |
1098 | } else | 1219 | } else if (is_blade(chip_id)) { |
1099 | if (is_blade(chip_id)) { | ||
1100 | acc = &accel_blade; | 1220 | acc = &accel_blade; |
1101 | } else { | 1221 | } else { |
1102 | acc = &accel_image; | 1222 | acc = &accel_image; |
@@ -1108,8 +1228,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1108 | fb_info.par = &default_par; | 1228 | fb_info.par = &default_par; |
1109 | 1229 | ||
1110 | /* setup MMIO region */ | 1230 | /* setup MMIO region */ |
1111 | tridentfb_fix.mmio_start = pci_resource_start(dev,1); | 1231 | tridentfb_fix.mmio_start = pci_resource_start(dev, 1); |
1112 | tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000; | 1232 | tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000; |
1113 | 1233 | ||
1114 | if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) { | 1234 | if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) { |
1115 | debug("request_region failed!\n"); | 1235 | debug("request_region failed!\n"); |
@@ -1125,11 +1245,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1125 | } | 1245 | } |
1126 | 1246 | ||
1127 | enable_mmio(); | 1247 | enable_mmio(); |
1128 | 1248 | ||
1129 | /* setup framebuffer memory */ | 1249 | /* setup framebuffer memory */ |
1130 | tridentfb_fix.smem_start = pci_resource_start(dev,0); | 1250 | tridentfb_fix.smem_start = pci_resource_start(dev, 0); |
1131 | tridentfb_fix.smem_len = get_memsize(); | 1251 | tridentfb_fix.smem_len = get_memsize(); |
1132 | 1252 | ||
1133 | if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { | 1253 | if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { |
1134 | debug("request_mem_region failed!\n"); | 1254 | debug("request_mem_region failed!\n"); |
1135 | err = -1; | 1255 | err = -1; |
@@ -1137,7 +1257,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1137 | } | 1257 | } |
1138 | 1258 | ||
1139 | fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, | 1259 | fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, |
1140 | tridentfb_fix.smem_len); | 1260 | tridentfb_fix.smem_len); |
1141 | 1261 | ||
1142 | if (!fb_info.screen_base) { | 1262 | if (!fb_info.screen_base) { |
1143 | release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); | 1263 | release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); |
@@ -1147,13 +1267,13 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1147 | } | 1267 | } |
1148 | 1268 | ||
1149 | output("%s board found\n", pci_name(dev)); | 1269 | output("%s board found\n", pci_name(dev)); |
1150 | #if 0 | 1270 | #if 0 |
1151 | output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n", | 1271 | output("Trident board found : mem = %X, io = %X, mem_v = %X, io_v = %X\n", |
1152 | tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt); | 1272 | tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt); |
1153 | #endif | 1273 | #endif |
1154 | displaytype = get_displaytype(); | 1274 | displaytype = get_displaytype(); |
1155 | 1275 | ||
1156 | if(flatpanel) | 1276 | if (flatpanel) |
1157 | nativex = get_nativex(); | 1277 | nativex = get_nativex(); |
1158 | 1278 | ||
1159 | fb_info.fix = tridentfb_fix; | 1279 | fb_info.fix = tridentfb_fix; |
@@ -1166,11 +1286,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1166 | #endif | 1286 | #endif |
1167 | fb_info.pseudo_palette = pseudo_pal; | 1287 | fb_info.pseudo_palette = pseudo_pal; |
1168 | 1288 | ||
1169 | if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) { | 1289 | if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { |
1170 | err = -EINVAL; | 1290 | err = -EINVAL; |
1171 | goto out_unmap; | 1291 | goto out_unmap; |
1172 | } | 1292 | } |
1173 | fb_alloc_cmap(&fb_info.cmap,256,0); | 1293 | fb_alloc_cmap(&fb_info.cmap, 256, 0); |
1174 | if (defaultaccel && acc) | 1294 | if (defaultaccel && acc) |
1175 | default_var.accel_flags |= FB_ACCELF_TEXT; | 1295 | default_var.accel_flags |= FB_ACCELF_TEXT; |
1176 | else | 1296 | else |
@@ -1184,8 +1304,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de | |||
1184 | goto out_unmap; | 1304 | goto out_unmap; |
1185 | } | 1305 | } |
1186 | output("fb%d: %s frame buffer device %dx%d-%dbpp\n", | 1306 | output("fb%d: %s frame buffer device %dx%d-%dbpp\n", |
1187 | fb_info.node, fb_info.fix.id,default_var.xres, | 1307 | fb_info.node, fb_info.fix.id, default_var.xres, |
1188 | default_var.yres,default_var.bits_per_pixel); | 1308 | default_var.yres, default_var.bits_per_pixel); |
1189 | return 0; | 1309 | return 0; |
1190 | 1310 | ||
1191 | out_unmap: | 1311 | out_unmap: |
@@ -1196,7 +1316,7 @@ out_unmap: | |||
1196 | return err; | 1316 | return err; |
1197 | } | 1317 | } |
1198 | 1318 | ||
1199 | static void __devexit trident_pci_remove(struct pci_dev * dev) | 1319 | static void __devexit trident_pci_remove(struct pci_dev *dev) |
1200 | { | 1320 | { |
1201 | struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par; | 1321 | struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par; |
1202 | unregister_framebuffer(&fb_info); | 1322 | unregister_framebuffer(&fb_info); |
@@ -1208,69 +1328,70 @@ static void __devexit trident_pci_remove(struct pci_dev * dev) | |||
1208 | 1328 | ||
1209 | /* List of boards that we are trying to support */ | 1329 | /* List of boards that we are trying to support */ |
1210 | static struct pci_device_id trident_devices[] = { | 1330 | static struct pci_device_id trident_devices[] = { |
1211 | {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1331 | {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1212 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1332 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1213 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1333 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1214 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1334 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1215 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1335 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1216 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1336 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1217 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1337 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1218 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1338 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1219 | {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1339 | {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1220 | {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1340 | {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1221 | {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1341 | {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1222 | {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1342 | {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1223 | {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1343 | {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1224 | {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1344 | {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1225 | {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1345 | {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1226 | {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1346 | {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1227 | {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1347 | {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1228 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1348 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1229 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1349 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1230 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, | 1350 | {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
1231 | {0,} | 1351 | {0,} |
1232 | }; | 1352 | }; |
1233 | 1353 | ||
1234 | MODULE_DEVICE_TABLE(pci,trident_devices); | 1354 | MODULE_DEVICE_TABLE(pci, trident_devices); |
1235 | 1355 | ||
1236 | static struct pci_driver tridentfb_pci_driver = { | 1356 | static struct pci_driver tridentfb_pci_driver = { |
1237 | .name = "tridentfb", | 1357 | .name = "tridentfb", |
1238 | .id_table = trident_devices, | 1358 | .id_table = trident_devices, |
1239 | .probe = trident_pci_probe, | 1359 | .probe = trident_pci_probe, |
1240 | .remove = __devexit_p(trident_pci_remove) | 1360 | .remove = __devexit_p(trident_pci_remove) |
1241 | }; | 1361 | }; |
1242 | 1362 | ||
1243 | /* | 1363 | /* |
1244 | * Parse user specified options (`video=trident:') | 1364 | * Parse user specified options (`video=trident:') |
1245 | * example: | 1365 | * example: |
1246 | * video=trident:800x600,bpp=16,noaccel | 1366 | * video=trident:800x600,bpp=16,noaccel |
1247 | */ | 1367 | */ |
1248 | #ifndef MODULE | 1368 | #ifndef MODULE |
1249 | static int tridentfb_setup(char *options) | 1369 | static int tridentfb_setup(char *options) |
1250 | { | 1370 | { |
1251 | char * opt; | 1371 | char *opt; |
1252 | if (!options || !*options) | 1372 | if (!options || !*options) |
1253 | return 0; | 1373 | return 0; |
1254 | while((opt = strsep(&options,",")) != NULL ) { | 1374 | while ((opt = strsep(&options, ",")) != NULL) { |
1255 | if (!*opt) continue; | 1375 | if (!*opt) |
1256 | if (!strncmp(opt,"noaccel",7)) | 1376 | continue; |
1377 | if (!strncmp(opt, "noaccel", 7)) | ||
1257 | noaccel = 1; | 1378 | noaccel = 1; |
1258 | else if (!strncmp(opt,"fp",2)) | 1379 | else if (!strncmp(opt, "fp", 2)) |
1259 | displaytype = DISPLAY_FP; | 1380 | displaytype = DISPLAY_FP; |
1260 | else if (!strncmp(opt,"crt",3)) | 1381 | else if (!strncmp(opt, "crt", 3)) |
1261 | displaytype = DISPLAY_CRT; | 1382 | displaytype = DISPLAY_CRT; |
1262 | else if (!strncmp(opt,"bpp=",4)) | 1383 | else if (!strncmp(opt, "bpp=", 4)) |
1263 | bpp = simple_strtoul(opt+4,NULL,0); | 1384 | bpp = simple_strtoul(opt + 4, NULL, 0); |
1264 | else if (!strncmp(opt,"center",6)) | 1385 | else if (!strncmp(opt, "center", 6)) |
1265 | center = 1; | 1386 | center = 1; |
1266 | else if (!strncmp(opt,"stretch",7)) | 1387 | else if (!strncmp(opt, "stretch", 7)) |
1267 | stretch = 1; | 1388 | stretch = 1; |
1268 | else if (!strncmp(opt,"memsize=",8)) | 1389 | else if (!strncmp(opt, "memsize=", 8)) |
1269 | memsize = simple_strtoul(opt+8,NULL,0); | 1390 | memsize = simple_strtoul(opt + 8, NULL, 0); |
1270 | else if (!strncmp(opt,"memdiff=",8)) | 1391 | else if (!strncmp(opt, "memdiff=", 8)) |
1271 | memdiff = simple_strtoul(opt+8,NULL,0); | 1392 | memdiff = simple_strtoul(opt + 8, NULL, 0); |
1272 | else if (!strncmp(opt,"nativex=",8)) | 1393 | else if (!strncmp(opt, "nativex=", 8)) |
1273 | nativex = simple_strtoul(opt+8,NULL,0); | 1394 | nativex = simple_strtoul(opt + 8, NULL, 0); |
1274 | else | 1395 | else |
1275 | mode = opt; | 1396 | mode = opt; |
1276 | } | 1397 | } |
@@ -1296,18 +1417,6 @@ static void __exit tridentfb_exit(void) | |||
1296 | pci_unregister_driver(&tridentfb_pci_driver); | 1417 | pci_unregister_driver(&tridentfb_pci_driver); |
1297 | } | 1418 | } |
1298 | 1419 | ||
1299 | static struct fb_ops tridentfb_ops = { | ||
1300 | .owner = THIS_MODULE, | ||
1301 | .fb_setcolreg = tridentfb_setcolreg, | ||
1302 | .fb_pan_display = tridentfb_pan_display, | ||
1303 | .fb_blank = tridentfb_blank, | ||
1304 | .fb_check_var = tridentfb_check_var, | ||
1305 | .fb_set_par = tridentfb_set_par, | ||
1306 | .fb_fillrect = tridentfb_fillrect, | ||
1307 | .fb_copyarea= tridentfb_copyarea, | ||
1308 | .fb_imageblit = cfb_imageblit, | ||
1309 | }; | ||
1310 | |||
1311 | module_init(tridentfb_init); | 1420 | module_init(tridentfb_init); |
1312 | module_exit(tridentfb_exit); | 1421 | module_exit(tridentfb_exit); |
1313 | 1422 | ||
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c new file mode 100644 index 000000000000..b983d262ab78 --- /dev/null +++ b/drivers/video/uvesafb.c | |||
@@ -0,0 +1,2066 @@ | |||
1 | /* | ||
2 | * A framebuffer driver for VBE 2.0+ compliant video cards | ||
3 | * | ||
4 | * (c) 2007 Michal Januszewski <spock@gentoo.org> | ||
5 | * Loosely based upon the vesafb driver. | ||
6 | * | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/moduleparam.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/timer.h> | ||
13 | #include <linux/completion.h> | ||
14 | #include <linux/connector.h> | ||
15 | #include <linux/random.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/limits.h> | ||
18 | #include <linux/fb.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <video/edid.h> | ||
22 | #include <video/uvesafb.h> | ||
23 | #ifdef CONFIG_X86 | ||
24 | #include <video/vga.h> | ||
25 | #endif | ||
26 | #ifdef CONFIG_MTRR | ||
27 | #include <asm/mtrr.h> | ||
28 | #endif | ||
29 | #include "edid.h" | ||
30 | |||
31 | static struct cb_id uvesafb_cn_id = { | ||
32 | .idx = CN_IDX_V86D, | ||
33 | .val = CN_VAL_V86D_UVESAFB | ||
34 | }; | ||
35 | static char v86d_path[PATH_MAX] = "/sbin/v86d"; | ||
36 | static char v86d_started; /* has v86d been started by uvesafb? */ | ||
37 | |||
38 | static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { | ||
39 | .id = "VESA VGA", | ||
40 | .type = FB_TYPE_PACKED_PIXELS, | ||
41 | .accel = FB_ACCEL_NONE, | ||
42 | .visual = FB_VISUAL_TRUECOLOR, | ||
43 | }; | ||
44 | |||
45 | static int mtrr __devinitdata = 3; /* enable mtrr by default */ | ||
46 | static int blank __devinitdata = 1; /* enable blanking by default */ | ||
47 | static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */ | ||
48 | static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */ | ||
49 | static int nocrtc __devinitdata; /* ignore CRTC settings */ | ||
50 | static int noedid __devinitdata; /* don't try DDC transfers */ | ||
51 | static int vram_remap __devinitdata; /* set amt. of memory to be used */ | ||
52 | static int vram_total __devinitdata; /* set total amount of memory */ | ||
53 | static u16 maxclk __devinitdata; /* maximum pixel clock */ | ||
54 | static u16 maxvf __devinitdata; /* maximum vertical frequency */ | ||
55 | static u16 maxhf __devinitdata; /* maximum horizontal frequency */ | ||
56 | static u16 vbemode __devinitdata; /* force use of a specific VBE mode */ | ||
57 | static char *mode_option __devinitdata; | ||
58 | |||
59 | static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX]; | ||
60 | static DEFINE_MUTEX(uvfb_lock); | ||
61 | |||
62 | /* | ||
63 | * A handler for replies from userspace. | ||
64 | * | ||
65 | * Make sure each message passes consistency checks and if it does, | ||
66 | * find the kernel part of the task struct, copy the registers and | ||
67 | * the buffer contents and then complete the task. | ||
68 | */ | ||
69 | static void uvesafb_cn_callback(void *data) | ||
70 | { | ||
71 | struct cn_msg *msg = data; | ||
72 | struct uvesafb_task *utask; | ||
73 | struct uvesafb_ktask *task; | ||
74 | |||
75 | if (msg->seq >= UVESAFB_TASKS_MAX) | ||
76 | return; | ||
77 | |||
78 | mutex_lock(&uvfb_lock); | ||
79 | task = uvfb_tasks[msg->seq]; | ||
80 | |||
81 | if (!task || msg->ack != task->ack) { | ||
82 | mutex_unlock(&uvfb_lock); | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | utask = (struct uvesafb_task *)msg->data; | ||
87 | |||
88 | /* Sanity checks for the buffer length. */ | ||
89 | if (task->t.buf_len < utask->buf_len || | ||
90 | utask->buf_len > msg->len - sizeof(*utask)) { | ||
91 | mutex_unlock(&uvfb_lock); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | uvfb_tasks[msg->seq] = NULL; | ||
96 | mutex_unlock(&uvfb_lock); | ||
97 | |||
98 | memcpy(&task->t, utask, sizeof(*utask)); | ||
99 | |||
100 | if (task->t.buf_len && task->buf) | ||
101 | memcpy(task->buf, utask + 1, task->t.buf_len); | ||
102 | |||
103 | complete(task->done); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | static int uvesafb_helper_start(void) | ||
108 | { | ||
109 | char *envp[] = { | ||
110 | "HOME=/", | ||
111 | "PATH=/sbin:/bin", | ||
112 | NULL, | ||
113 | }; | ||
114 | |||
115 | char *argv[] = { | ||
116 | v86d_path, | ||
117 | NULL, | ||
118 | }; | ||
119 | |||
120 | return call_usermodehelper(v86d_path, argv, envp, 1); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Execute a uvesafb task. | ||
125 | * | ||
126 | * Returns 0 if the task is executed successfully. | ||
127 | * | ||
128 | * A message sent to the userspace consists of the uvesafb_task | ||
129 | * struct and (optionally) a buffer. The uvesafb_task struct is | ||
130 | * a simplified version of uvesafb_ktask (its kernel counterpart) | ||
131 | * containing only the register values, flags and the length of | ||
132 | * the buffer. | ||
133 | * | ||
134 | * Each message is assigned a sequence number (increased linearly) | ||
135 | * and a random ack number. The sequence number is used as a key | ||
136 | * for the uvfb_tasks array which holds pointers to uvesafb_ktask | ||
137 | * structs for all requests. | ||
138 | */ | ||
139 | static int uvesafb_exec(struct uvesafb_ktask *task) | ||
140 | { | ||
141 | static int seq; | ||
142 | struct cn_msg *m; | ||
143 | int err; | ||
144 | int len = sizeof(task->t) + task->t.buf_len; | ||
145 | |||
146 | /* | ||
147 | * Check whether the message isn't longer than the maximum | ||
148 | * allowed by connector. | ||
149 | */ | ||
150 | if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) { | ||
151 | printk(KERN_WARNING "uvesafb: message too long (%d), " | ||
152 | "can't execute task\n", (int)(sizeof(*m) + len)); | ||
153 | return -E2BIG; | ||
154 | } | ||
155 | |||
156 | m = kzalloc(sizeof(*m) + len, GFP_KERNEL); | ||
157 | if (!m) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | init_completion(task->done); | ||
161 | |||
162 | memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id)); | ||
163 | m->seq = seq; | ||
164 | m->len = len; | ||
165 | m->ack = random32(); | ||
166 | |||
167 | /* uvesafb_task structure */ | ||
168 | memcpy(m + 1, &task->t, sizeof(task->t)); | ||
169 | |||
170 | /* Buffer */ | ||
171 | memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len); | ||
172 | |||
173 | /* | ||
174 | * Save the message ack number so that we can find the kernel | ||
175 | * part of this task when a reply is received from userspace. | ||
176 | */ | ||
177 | task->ack = m->ack; | ||
178 | |||
179 | mutex_lock(&uvfb_lock); | ||
180 | |||
181 | /* If all slots are taken -- bail out. */ | ||
182 | if (uvfb_tasks[seq]) { | ||
183 | mutex_unlock(&uvfb_lock); | ||
184 | return -EBUSY; | ||
185 | } | ||
186 | |||
187 | /* Save a pointer to the kernel part of the task struct. */ | ||
188 | uvfb_tasks[seq] = task; | ||
189 | mutex_unlock(&uvfb_lock); | ||
190 | |||
191 | err = cn_netlink_send(m, 0, gfp_any()); | ||
192 | if (err == -ESRCH) { | ||
193 | /* | ||
194 | * Try to start the userspace helper if sending | ||
195 | * the request failed the first time. | ||
196 | */ | ||
197 | err = uvesafb_helper_start(); | ||
198 | if (err) { | ||
199 | printk(KERN_ERR "uvesafb: failed to execute %s\n", | ||
200 | v86d_path); | ||
201 | printk(KERN_ERR "uvesafb: make sure that the v86d " | ||
202 | "helper is installed and executable\n"); | ||
203 | } else { | ||
204 | v86d_started = 1; | ||
205 | err = cn_netlink_send(m, 0, gfp_any()); | ||
206 | } | ||
207 | } | ||
208 | kfree(m); | ||
209 | |||
210 | if (!err && !(task->t.flags & TF_EXIT)) | ||
211 | err = !wait_for_completion_timeout(task->done, | ||
212 | msecs_to_jiffies(UVESAFB_TIMEOUT)); | ||
213 | |||
214 | mutex_lock(&uvfb_lock); | ||
215 | uvfb_tasks[seq] = NULL; | ||
216 | mutex_unlock(&uvfb_lock); | ||
217 | |||
218 | seq++; | ||
219 | if (seq >= UVESAFB_TASKS_MAX) | ||
220 | seq = 0; | ||
221 | |||
222 | return err; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Free a uvesafb_ktask struct. | ||
227 | */ | ||
228 | static void uvesafb_free(struct uvesafb_ktask *task) | ||
229 | { | ||
230 | if (task) { | ||
231 | if (task->done) | ||
232 | kfree(task->done); | ||
233 | kfree(task); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Prepare a uvesafb_ktask struct to be used again. | ||
239 | */ | ||
240 | static void uvesafb_reset(struct uvesafb_ktask *task) | ||
241 | { | ||
242 | struct completion *cpl = task->done; | ||
243 | |||
244 | memset(task, 0, sizeof(*task)); | ||
245 | task->done = cpl; | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Allocate and prepare a uvesafb_ktask struct. | ||
250 | */ | ||
251 | static struct uvesafb_ktask *uvesafb_prep(void) | ||
252 | { | ||
253 | struct uvesafb_ktask *task; | ||
254 | |||
255 | task = kzalloc(sizeof(*task), GFP_KERNEL); | ||
256 | if (task) { | ||
257 | task->done = kzalloc(sizeof(*task->done), GFP_KERNEL); | ||
258 | if (!task->done) { | ||
259 | kfree(task); | ||
260 | task = NULL; | ||
261 | } | ||
262 | } | ||
263 | return task; | ||
264 | } | ||
265 | |||
266 | static void uvesafb_setup_var(struct fb_var_screeninfo *var, | ||
267 | struct fb_info *info, struct vbe_mode_ib *mode) | ||
268 | { | ||
269 | struct uvesafb_par *par = info->par; | ||
270 | |||
271 | var->vmode = FB_VMODE_NONINTERLACED; | ||
272 | var->sync = FB_SYNC_VERT_HIGH_ACT; | ||
273 | |||
274 | var->xres = mode->x_res; | ||
275 | var->yres = mode->y_res; | ||
276 | var->xres_virtual = mode->x_res; | ||
277 | var->yres_virtual = (par->ypan) ? | ||
278 | info->fix.smem_len / mode->bytes_per_scan_line : | ||
279 | mode->y_res; | ||
280 | var->xoffset = 0; | ||
281 | var->yoffset = 0; | ||
282 | var->bits_per_pixel = mode->bits_per_pixel; | ||
283 | |||
284 | if (var->bits_per_pixel == 15) | ||
285 | var->bits_per_pixel = 16; | ||
286 | |||
287 | if (var->bits_per_pixel > 8) { | ||
288 | var->red.offset = mode->red_off; | ||
289 | var->red.length = mode->red_len; | ||
290 | var->green.offset = mode->green_off; | ||
291 | var->green.length = mode->green_len; | ||
292 | var->blue.offset = mode->blue_off; | ||
293 | var->blue.length = mode->blue_len; | ||
294 | var->transp.offset = mode->rsvd_off; | ||
295 | var->transp.length = mode->rsvd_len; | ||
296 | } else { | ||
297 | var->red.offset = 0; | ||
298 | var->green.offset = 0; | ||
299 | var->blue.offset = 0; | ||
300 | var->transp.offset = 0; | ||
301 | |||
302 | /* | ||
303 | * We're assuming that we can switch the DAC to 8 bits. If | ||
304 | * this proves to be incorrect, we'll update the fields | ||
305 | * later in set_par(). | ||
306 | */ | ||
307 | if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) { | ||
308 | var->red.length = 8; | ||
309 | var->green.length = 8; | ||
310 | var->blue.length = 8; | ||
311 | var->transp.length = 0; | ||
312 | } else { | ||
313 | var->red.length = 6; | ||
314 | var->green.length = 6; | ||
315 | var->blue.length = 6; | ||
316 | var->transp.length = 0; | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static int uvesafb_vbe_find_mode(struct uvesafb_par *par, | ||
322 | int xres, int yres, int depth, unsigned char flags) | ||
323 | { | ||
324 | int i, match = -1, h = 0, d = 0x7fffffff; | ||
325 | |||
326 | for (i = 0; i < par->vbe_modes_cnt; i++) { | ||
327 | h = abs(par->vbe_modes[i].x_res - xres) + | ||
328 | abs(par->vbe_modes[i].y_res - yres) + | ||
329 | abs(depth - par->vbe_modes[i].depth); | ||
330 | |||
331 | /* | ||
332 | * We have an exact match in terms of resolution | ||
333 | * and depth. | ||
334 | */ | ||
335 | if (h == 0) | ||
336 | return i; | ||
337 | |||
338 | if (h < d || (h == d && par->vbe_modes[i].depth > depth)) { | ||
339 | d = h; | ||
340 | match = i; | ||
341 | } | ||
342 | } | ||
343 | i = 1; | ||
344 | |||
345 | if (flags & UVESAFB_EXACT_DEPTH && | ||
346 | par->vbe_modes[match].depth != depth) | ||
347 | i = 0; | ||
348 | |||
349 | if (flags & UVESAFB_EXACT_RES && d > 24) | ||
350 | i = 0; | ||
351 | |||
352 | if (i != 0) | ||
353 | return match; | ||
354 | else | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par) | ||
359 | { | ||
360 | struct uvesafb_ktask *task; | ||
361 | u8 *state; | ||
362 | int err; | ||
363 | |||
364 | if (!par->vbe_state_size) | ||
365 | return NULL; | ||
366 | |||
367 | state = kmalloc(par->vbe_state_size, GFP_KERNEL); | ||
368 | if (!state) | ||
369 | return NULL; | ||
370 | |||
371 | task = uvesafb_prep(); | ||
372 | if (!task) { | ||
373 | kfree(state); | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | task->t.regs.eax = 0x4f04; | ||
378 | task->t.regs.ecx = 0x000f; | ||
379 | task->t.regs.edx = 0x0001; | ||
380 | task->t.flags = TF_BUF_RET | TF_BUF_ESBX; | ||
381 | task->t.buf_len = par->vbe_state_size; | ||
382 | task->buf = state; | ||
383 | err = uvesafb_exec(task); | ||
384 | |||
385 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) { | ||
386 | printk(KERN_WARNING "uvesafb: VBE get state call " | ||
387 | "failed (eax=0x%x, err=%d)\n", | ||
388 | task->t.regs.eax, err); | ||
389 | kfree(state); | ||
390 | state = NULL; | ||
391 | } | ||
392 | |||
393 | uvesafb_free(task); | ||
394 | return state; | ||
395 | } | ||
396 | |||
397 | static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf) | ||
398 | { | ||
399 | struct uvesafb_ktask *task; | ||
400 | int err; | ||
401 | |||
402 | if (!state_buf) | ||
403 | return; | ||
404 | |||
405 | task = uvesafb_prep(); | ||
406 | if (!task) | ||
407 | return; | ||
408 | |||
409 | task->t.regs.eax = 0x4f04; | ||
410 | task->t.regs.ecx = 0x000f; | ||
411 | task->t.regs.edx = 0x0002; | ||
412 | task->t.buf_len = par->vbe_state_size; | ||
413 | task->t.flags = TF_BUF_ESBX; | ||
414 | task->buf = state_buf; | ||
415 | |||
416 | err = uvesafb_exec(task); | ||
417 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) | ||
418 | printk(KERN_WARNING "uvesafb: VBE state restore call " | ||
419 | "failed (eax=0x%x, err=%d)\n", | ||
420 | task->t.regs.eax, err); | ||
421 | |||
422 | uvesafb_free(task); | ||
423 | } | ||
424 | |||
425 | static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task, | ||
426 | struct uvesafb_par *par) | ||
427 | { | ||
428 | int err; | ||
429 | |||
430 | task->t.regs.eax = 0x4f00; | ||
431 | task->t.flags = TF_VBEIB; | ||
432 | task->t.buf_len = sizeof(struct vbe_ib); | ||
433 | task->buf = &par->vbe_ib; | ||
434 | strncpy(par->vbe_ib.vbe_signature, "VBE2", 4); | ||
435 | |||
436 | err = uvesafb_exec(task); | ||
437 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) { | ||
438 | printk(KERN_ERR "uvesafb: Getting VBE info block failed " | ||
439 | "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax, | ||
440 | err); | ||
441 | return -EINVAL; | ||
442 | } | ||
443 | |||
444 | if (par->vbe_ib.vbe_version < 0x0200) { | ||
445 | printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are " | ||
446 | "not supported.\n"); | ||
447 | return -EINVAL; | ||
448 | } | ||
449 | |||
450 | if (!par->vbe_ib.mode_list_ptr) { | ||
451 | printk(KERN_ERR "uvesafb: Missing mode list!\n"); | ||
452 | return -EINVAL; | ||
453 | } | ||
454 | |||
455 | printk(KERN_INFO "uvesafb: "); | ||
456 | |||
457 | /* | ||
458 | * Convert string pointers and the mode list pointer into | ||
459 | * usable addresses. Print informational messages about the | ||
460 | * video adapter and its vendor. | ||
461 | */ | ||
462 | if (par->vbe_ib.oem_vendor_name_ptr) | ||
463 | printk("%s, ", | ||
464 | ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr); | ||
465 | |||
466 | if (par->vbe_ib.oem_product_name_ptr) | ||
467 | printk("%s, ", | ||
468 | ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr); | ||
469 | |||
470 | if (par->vbe_ib.oem_product_rev_ptr) | ||
471 | printk("%s, ", | ||
472 | ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr); | ||
473 | |||
474 | if (par->vbe_ib.oem_string_ptr) | ||
475 | printk("OEM: %s, ", | ||
476 | ((char *)task->buf) + par->vbe_ib.oem_string_ptr); | ||
477 | |||
478 | printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8), | ||
479 | par->vbe_ib.vbe_version & 0xff); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task, | ||
485 | struct uvesafb_par *par) | ||
486 | { | ||
487 | int off = 0, err; | ||
488 | u16 *mode; | ||
489 | |||
490 | par->vbe_modes_cnt = 0; | ||
491 | |||
492 | /* Count available modes. */ | ||
493 | mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); | ||
494 | while (*mode != 0xffff) { | ||
495 | par->vbe_modes_cnt++; | ||
496 | mode++; | ||
497 | } | ||
498 | |||
499 | par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) * | ||
500 | par->vbe_modes_cnt, GFP_KERNEL); | ||
501 | if (!par->vbe_modes) | ||
502 | return -ENOMEM; | ||
503 | |||
504 | /* Get info about all available modes. */ | ||
505 | mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); | ||
506 | while (*mode != 0xffff) { | ||
507 | struct vbe_mode_ib *mib; | ||
508 | |||
509 | uvesafb_reset(task); | ||
510 | task->t.regs.eax = 0x4f01; | ||
511 | task->t.regs.ecx = (u32) *mode; | ||
512 | task->t.flags = TF_BUF_RET | TF_BUF_ESDI; | ||
513 | task->t.buf_len = sizeof(struct vbe_mode_ib); | ||
514 | task->buf = par->vbe_modes + off; | ||
515 | |||
516 | err = uvesafb_exec(task); | ||
517 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) { | ||
518 | printk(KERN_ERR "uvesafb: Getting mode info block " | ||
519 | "for mode 0x%x failed (eax=0x%x, err=%d)\n", | ||
520 | *mode, (u32)task->t.regs.eax, err); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | mib = task->buf; | ||
525 | mib->mode_id = *mode; | ||
526 | |||
527 | /* | ||
528 | * We only want modes that are supported with the current | ||
529 | * hardware configuration, color, graphics and that have | ||
530 | * support for the LFB. | ||
531 | */ | ||
532 | if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK && | ||
533 | mib->bits_per_pixel >= 8) | ||
534 | off++; | ||
535 | else | ||
536 | par->vbe_modes_cnt--; | ||
537 | |||
538 | mode++; | ||
539 | mib->depth = mib->red_len + mib->green_len + mib->blue_len; | ||
540 | |||
541 | /* | ||
542 | * Handle 8bpp modes and modes with broken color component | ||
543 | * lengths. | ||
544 | */ | ||
545 | if (mib->depth == 0 || (mib->depth == 24 && | ||
546 | mib->bits_per_pixel == 32)) | ||
547 | mib->depth = mib->bits_per_pixel; | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * The Protected Mode Interface is 32-bit x86 code, so we only run it on | ||
555 | * x86 and not x86_64. | ||
556 | */ | ||
557 | #ifdef CONFIG_X86_32 | ||
558 | static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task, | ||
559 | struct uvesafb_par *par) | ||
560 | { | ||
561 | int i, err; | ||
562 | |||
563 | uvesafb_reset(task); | ||
564 | task->t.regs.eax = 0x4f0a; | ||
565 | task->t.regs.ebx = 0x0; | ||
566 | err = uvesafb_exec(task); | ||
567 | |||
568 | if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) { | ||
569 | par->pmi_setpal = par->ypan = 0; | ||
570 | } else { | ||
571 | par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4) | ||
572 | + task->t.regs.edi); | ||
573 | par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1]; | ||
574 | par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2]; | ||
575 | printk(KERN_INFO "uvesafb: protected mode interface info at " | ||
576 | "%04x:%04x\n", | ||
577 | (u16)task->t.regs.es, (u16)task->t.regs.edi); | ||
578 | printk(KERN_INFO "uvesafb: pmi: set display start = %p, " | ||
579 | "set palette = %p\n", par->pmi_start, | ||
580 | par->pmi_pal); | ||
581 | |||
582 | if (par->pmi_base[3]) { | ||
583 | printk(KERN_INFO "uvesafb: pmi: ports = "); | ||
584 | for (i = par->pmi_base[3]/2; | ||
585 | par->pmi_base[i] != 0xffff; i++) | ||
586 | printk("%x ", par->pmi_base[i]); | ||
587 | printk("\n"); | ||
588 | |||
589 | if (par->pmi_base[i] != 0xffff) { | ||
590 | printk(KERN_INFO "uvesafb: can't handle memory" | ||
591 | " requests, pmi disabled\n"); | ||
592 | par->ypan = par->pmi_setpal = 0; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | return 0; | ||
597 | } | ||
598 | #endif /* CONFIG_X86_32 */ | ||
599 | |||
600 | /* | ||
601 | * Check whether a video mode is supported by the Video BIOS and is | ||
602 | * compatible with the monitor limits. | ||
603 | */ | ||
604 | static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode, | ||
605 | struct fb_info *info) | ||
606 | { | ||
607 | if (info->monspecs.gtf) { | ||
608 | fb_videomode_to_var(&info->var, mode); | ||
609 | if (fb_validate_mode(&info->var, info)) | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8, | ||
614 | UVESAFB_EXACT_RES) == -1) | ||
615 | return 0; | ||
616 | |||
617 | return 1; | ||
618 | } | ||
619 | |||
620 | static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, | ||
621 | struct fb_info *info) | ||
622 | { | ||
623 | struct uvesafb_par *par = info->par; | ||
624 | int err = 0; | ||
625 | |||
626 | if (noedid || par->vbe_ib.vbe_version < 0x0300) | ||
627 | return -EINVAL; | ||
628 | |||
629 | task->t.regs.eax = 0x4f15; | ||
630 | task->t.regs.ebx = 0; | ||
631 | task->t.regs.ecx = 0; | ||
632 | task->t.buf_len = 0; | ||
633 | task->t.flags = 0; | ||
634 | |||
635 | err = uvesafb_exec(task); | ||
636 | |||
637 | if ((task->t.regs.eax & 0xffff) != 0x004f || err) | ||
638 | return -EINVAL; | ||
639 | |||
640 | if ((task->t.regs.ebx & 0x3) == 3) { | ||
641 | printk(KERN_INFO "uvesafb: VBIOS/hardware supports both " | ||
642 | "DDC1 and DDC2 transfers\n"); | ||
643 | } else if ((task->t.regs.ebx & 0x3) == 2) { | ||
644 | printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 " | ||
645 | "transfers\n"); | ||
646 | } else if ((task->t.regs.ebx & 0x3) == 1) { | ||
647 | printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 " | ||
648 | "transfers\n"); | ||
649 | } else { | ||
650 | printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support " | ||
651 | "DDC transfers\n"); | ||
652 | return -EINVAL; | ||
653 | } | ||
654 | |||
655 | task->t.regs.eax = 0x4f15; | ||
656 | task->t.regs.ebx = 1; | ||
657 | task->t.regs.ecx = task->t.regs.edx = 0; | ||
658 | task->t.flags = TF_BUF_RET | TF_BUF_ESDI; | ||
659 | task->t.buf_len = EDID_LENGTH; | ||
660 | task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); | ||
661 | |||
662 | err = uvesafb_exec(task); | ||
663 | |||
664 | if ((task->t.regs.eax & 0xffff) == 0x004f && !err) { | ||
665 | fb_edid_to_monspecs(task->buf, &info->monspecs); | ||
666 | |||
667 | if (info->monspecs.vfmax && info->monspecs.hfmax) { | ||
668 | /* | ||
669 | * If the maximum pixel clock wasn't specified in | ||
670 | * the EDID block, set it to 300 MHz. | ||
671 | */ | ||
672 | if (info->monspecs.dclkmax == 0) | ||
673 | info->monspecs.dclkmax = 300 * 1000000; | ||
674 | info->monspecs.gtf = 1; | ||
675 | } | ||
676 | } else { | ||
677 | err = -EINVAL; | ||
678 | } | ||
679 | |||
680 | kfree(task->buf); | ||
681 | return err; | ||
682 | } | ||
683 | |||
684 | static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task, | ||
685 | struct fb_info *info) | ||
686 | { | ||
687 | struct uvesafb_par *par = info->par; | ||
688 | int i; | ||
689 | |||
690 | memset(&info->monspecs, 0, sizeof(info->monspecs)); | ||
691 | |||
692 | /* | ||
693 | * If we don't get all necessary data from the EDID block, | ||
694 | * mark it as incompatible with the GTF and set nocrtc so | ||
695 | * that we always use the default BIOS refresh rate. | ||
696 | */ | ||
697 | if (uvesafb_vbe_getedid(task, info)) { | ||
698 | info->monspecs.gtf = 0; | ||
699 | par->nocrtc = 1; | ||
700 | } | ||
701 | |||
702 | /* Kernel command line overrides. */ | ||
703 | if (maxclk) | ||
704 | info->monspecs.dclkmax = maxclk * 1000000; | ||
705 | if (maxvf) | ||
706 | info->monspecs.vfmax = maxvf; | ||
707 | if (maxhf) | ||
708 | info->monspecs.hfmax = maxhf * 1000; | ||
709 | |||
710 | /* | ||
711 | * In case DDC transfers are not supported, the user can provide | ||
712 | * monitor limits manually. Lower limits are set to "safe" values. | ||
713 | */ | ||
714 | if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) { | ||
715 | info->monspecs.dclkmin = 0; | ||
716 | info->monspecs.vfmin = 60; | ||
717 | info->monspecs.hfmin = 29000; | ||
718 | info->monspecs.gtf = 1; | ||
719 | par->nocrtc = 0; | ||
720 | } | ||
721 | |||
722 | if (info->monspecs.gtf) | ||
723 | printk(KERN_INFO | ||
724 | "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, " | ||
725 | "clk = %d MHz\n", info->monspecs.vfmax, | ||
726 | (int)(info->monspecs.hfmax / 1000), | ||
727 | (int)(info->monspecs.dclkmax / 1000000)); | ||
728 | else | ||
729 | printk(KERN_INFO "uvesafb: no monitor limits have been set, " | ||
730 | "default refresh rate will be used\n"); | ||
731 | |||
732 | /* Add VBE modes to the modelist. */ | ||
733 | for (i = 0; i < par->vbe_modes_cnt; i++) { | ||
734 | struct fb_var_screeninfo var; | ||
735 | struct vbe_mode_ib *mode; | ||
736 | struct fb_videomode vmode; | ||
737 | |||
738 | mode = &par->vbe_modes[i]; | ||
739 | memset(&var, 0, sizeof(var)); | ||
740 | |||
741 | var.xres = mode->x_res; | ||
742 | var.yres = mode->y_res; | ||
743 | |||
744 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info); | ||
745 | fb_var_to_videomode(&vmode, &var); | ||
746 | fb_add_videomode(&vmode, &info->modelist); | ||
747 | } | ||
748 | |||
749 | /* Add valid VESA modes to our modelist. */ | ||
750 | for (i = 0; i < VESA_MODEDB_SIZE; i++) { | ||
751 | if (uvesafb_is_valid_mode((struct fb_videomode *) | ||
752 | &vesa_modes[i], info)) | ||
753 | fb_add_videomode(&vesa_modes[i], &info->modelist); | ||
754 | } | ||
755 | |||
756 | for (i = 0; i < info->monspecs.modedb_len; i++) { | ||
757 | if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info)) | ||
758 | fb_add_videomode(&info->monspecs.modedb[i], | ||
759 | &info->modelist); | ||
760 | } | ||
761 | |||
762 | return; | ||
763 | } | ||
764 | |||
765 | static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task, | ||
766 | struct uvesafb_par *par) | ||
767 | { | ||
768 | int err; | ||
769 | |||
770 | uvesafb_reset(task); | ||
771 | |||
772 | /* | ||
773 | * Get the VBE state buffer size. We want all available | ||
774 | * hardware state data (CL = 0x0f). | ||
775 | */ | ||
776 | task->t.regs.eax = 0x4f04; | ||
777 | task->t.regs.ecx = 0x000f; | ||
778 | task->t.regs.edx = 0x0000; | ||
779 | task->t.flags = 0; | ||
780 | |||
781 | err = uvesafb_exec(task); | ||
782 | |||
783 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) { | ||
784 | printk(KERN_WARNING "uvesafb: VBE state buffer size " | ||
785 | "cannot be determined (eax=0x%x, err=%d)\n", | ||
786 | task->t.regs.eax, err); | ||
787 | par->vbe_state_size = 0; | ||
788 | return; | ||
789 | } | ||
790 | |||
791 | par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff); | ||
792 | } | ||
793 | |||
794 | static int __devinit uvesafb_vbe_init(struct fb_info *info) | ||
795 | { | ||
796 | struct uvesafb_ktask *task = NULL; | ||
797 | struct uvesafb_par *par = info->par; | ||
798 | int err; | ||
799 | |||
800 | task = uvesafb_prep(); | ||
801 | if (!task) | ||
802 | return -ENOMEM; | ||
803 | |||
804 | err = uvesafb_vbe_getinfo(task, par); | ||
805 | if (err) | ||
806 | goto out; | ||
807 | |||
808 | err = uvesafb_vbe_getmodes(task, par); | ||
809 | if (err) | ||
810 | goto out; | ||
811 | |||
812 | par->nocrtc = nocrtc; | ||
813 | #ifdef CONFIG_X86_32 | ||
814 | par->pmi_setpal = pmi_setpal; | ||
815 | par->ypan = ypan; | ||
816 | |||
817 | if (par->pmi_setpal || par->ypan) | ||
818 | uvesafb_vbe_getpmi(task, par); | ||
819 | #else | ||
820 | /* The protected mode interface is not available on non-x86. */ | ||
821 | par->pmi_setpal = par->ypan = 0; | ||
822 | #endif | ||
823 | |||
824 | INIT_LIST_HEAD(&info->modelist); | ||
825 | uvesafb_vbe_getmonspecs(task, info); | ||
826 | uvesafb_vbe_getstatesize(task, par); | ||
827 | |||
828 | out: uvesafb_free(task); | ||
829 | return err; | ||
830 | } | ||
831 | |||
832 | static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) | ||
833 | { | ||
834 | struct list_head *pos; | ||
835 | struct fb_modelist *modelist; | ||
836 | struct fb_videomode *mode; | ||
837 | struct uvesafb_par *par = info->par; | ||
838 | int i, modeid; | ||
839 | |||
840 | /* Has the user requested a specific VESA mode? */ | ||
841 | if (vbemode) { | ||
842 | for (i = 0; i < par->vbe_modes_cnt; i++) { | ||
843 | if (par->vbe_modes[i].mode_id == vbemode) { | ||
844 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, | ||
845 | &info->var, info); | ||
846 | /* | ||
847 | * With pixclock set to 0, the default BIOS | ||
848 | * timings will be used in set_par(). | ||
849 | */ | ||
850 | info->var.pixclock = 0; | ||
851 | modeid = i; | ||
852 | goto gotmode; | ||
853 | } | ||
854 | } | ||
855 | printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is " | ||
856 | "unavailable\n", vbemode); | ||
857 | vbemode = 0; | ||
858 | } | ||
859 | |||
860 | /* Count the modes in the modelist */ | ||
861 | i = 0; | ||
862 | list_for_each(pos, &info->modelist) | ||
863 | i++; | ||
864 | |||
865 | /* | ||
866 | * Convert the modelist into a modedb so that we can use it with | ||
867 | * fb_find_mode(). | ||
868 | */ | ||
869 | mode = kzalloc(i * sizeof(*mode), GFP_KERNEL); | ||
870 | if (mode) { | ||
871 | i = 0; | ||
872 | list_for_each(pos, &info->modelist) { | ||
873 | modelist = list_entry(pos, struct fb_modelist, list); | ||
874 | mode[i] = modelist->mode; | ||
875 | i++; | ||
876 | } | ||
877 | |||
878 | if (!mode_option) | ||
879 | mode_option = UVESAFB_DEFAULT_MODE; | ||
880 | |||
881 | i = fb_find_mode(&info->var, info, mode_option, mode, i, | ||
882 | NULL, 8); | ||
883 | |||
884 | kfree(mode); | ||
885 | } | ||
886 | |||
887 | /* fb_find_mode() failed */ | ||
888 | if (i == 0 || i >= 3) { | ||
889 | info->var.xres = 640; | ||
890 | info->var.yres = 480; | ||
891 | mode = (struct fb_videomode *) | ||
892 | fb_find_best_mode(&info->var, &info->modelist); | ||
893 | |||
894 | if (mode) { | ||
895 | fb_videomode_to_var(&info->var, mode); | ||
896 | } else { | ||
897 | modeid = par->vbe_modes[0].mode_id; | ||
898 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, | ||
899 | &info->var, info); | ||
900 | goto gotmode; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | /* Look for a matching VBE mode. */ | ||
905 | modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, | ||
906 | info->var.bits_per_pixel, UVESAFB_EXACT_RES); | ||
907 | |||
908 | if (modeid == -1) | ||
909 | return -EINVAL; | ||
910 | |||
911 | gotmode: | ||
912 | uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]); | ||
913 | |||
914 | /* | ||
915 | * If we are not VBE3.0+ compliant, we're done -- the BIOS will | ||
916 | * ignore our timings anyway. | ||
917 | */ | ||
918 | if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc) | ||
919 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, | ||
920 | &info->var, info); | ||
921 | |||
922 | return modeid; | ||
923 | } | ||
924 | |||
925 | static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count, | ||
926 | int start, struct fb_info *info) | ||
927 | { | ||
928 | struct uvesafb_ktask *task; | ||
929 | struct uvesafb_par *par = info->par; | ||
930 | int i = par->mode_idx; | ||
931 | int err = 0; | ||
932 | |||
933 | /* | ||
934 | * We support palette modifications for 8 bpp modes only, so | ||
935 | * there can never be more than 256 entries. | ||
936 | */ | ||
937 | if (start + count > 256) | ||
938 | return -EINVAL; | ||
939 | |||
940 | #ifdef CONFIG_X86 | ||
941 | /* Use VGA registers if mode is VGA-compatible. */ | ||
942 | if (i >= 0 && i < par->vbe_modes_cnt && | ||
943 | par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) { | ||
944 | for (i = 0; i < count; i++) { | ||
945 | outb_p(start + i, dac_reg); | ||
946 | outb_p(entries[i].red, dac_val); | ||
947 | outb_p(entries[i].green, dac_val); | ||
948 | outb_p(entries[i].blue, dac_val); | ||
949 | } | ||
950 | } | ||
951 | #ifdef CONFIG_X86_32 | ||
952 | else if (par->pmi_setpal) { | ||
953 | __asm__ __volatile__( | ||
954 | "call *(%%esi)" | ||
955 | : /* no return value */ | ||
956 | : "a" (0x4f09), /* EAX */ | ||
957 | "b" (0), /* EBX */ | ||
958 | "c" (count), /* ECX */ | ||
959 | "d" (start), /* EDX */ | ||
960 | "D" (entries), /* EDI */ | ||
961 | "S" (&par->pmi_pal)); /* ESI */ | ||
962 | } | ||
963 | #endif /* CONFIG_X86_32 */ | ||
964 | else | ||
965 | #endif /* CONFIG_X86 */ | ||
966 | { | ||
967 | task = uvesafb_prep(); | ||
968 | if (!task) | ||
969 | return -ENOMEM; | ||
970 | |||
971 | task->t.regs.eax = 0x4f09; | ||
972 | task->t.regs.ebx = 0x0; | ||
973 | task->t.regs.ecx = count; | ||
974 | task->t.regs.edx = start; | ||
975 | task->t.flags = TF_BUF_ESDI; | ||
976 | task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count; | ||
977 | task->buf = entries; | ||
978 | |||
979 | err = uvesafb_exec(task); | ||
980 | if ((task->t.regs.eax & 0xffff) != 0x004f) | ||
981 | err = 1; | ||
982 | |||
983 | uvesafb_free(task); | ||
984 | } | ||
985 | return err; | ||
986 | } | ||
987 | |||
988 | static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
989 | unsigned blue, unsigned transp, | ||
990 | struct fb_info *info) | ||
991 | { | ||
992 | struct uvesafb_pal_entry entry; | ||
993 | int shift = 16 - info->var.green.length; | ||
994 | int err = 0; | ||
995 | |||
996 | if (regno >= info->cmap.len) | ||
997 | return -EINVAL; | ||
998 | |||
999 | if (info->var.bits_per_pixel == 8) { | ||
1000 | entry.red = red >> shift; | ||
1001 | entry.green = green >> shift; | ||
1002 | entry.blue = blue >> shift; | ||
1003 | entry.pad = 0; | ||
1004 | |||
1005 | err = uvesafb_setpalette(&entry, 1, regno, info); | ||
1006 | } else if (regno < 16) { | ||
1007 | switch (info->var.bits_per_pixel) { | ||
1008 | case 16: | ||
1009 | if (info->var.red.offset == 10) { | ||
1010 | /* 1:5:5:5 */ | ||
1011 | ((u32 *) (info->pseudo_palette))[regno] = | ||
1012 | ((red & 0xf800) >> 1) | | ||
1013 | ((green & 0xf800) >> 6) | | ||
1014 | ((blue & 0xf800) >> 11); | ||
1015 | } else { | ||
1016 | /* 0:5:6:5 */ | ||
1017 | ((u32 *) (info->pseudo_palette))[regno] = | ||
1018 | ((red & 0xf800) ) | | ||
1019 | ((green & 0xfc00) >> 5) | | ||
1020 | ((blue & 0xf800) >> 11); | ||
1021 | } | ||
1022 | break; | ||
1023 | |||
1024 | case 24: | ||
1025 | case 32: | ||
1026 | red >>= 8; | ||
1027 | green >>= 8; | ||
1028 | blue >>= 8; | ||
1029 | ((u32 *)(info->pseudo_palette))[regno] = | ||
1030 | (red << info->var.red.offset) | | ||
1031 | (green << info->var.green.offset) | | ||
1032 | (blue << info->var.blue.offset); | ||
1033 | break; | ||
1034 | } | ||
1035 | } | ||
1036 | return err; | ||
1037 | } | ||
1038 | |||
1039 | static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
1040 | { | ||
1041 | struct uvesafb_pal_entry *entries; | ||
1042 | int shift = 16 - info->var.green.length; | ||
1043 | int i, err = 0; | ||
1044 | |||
1045 | if (info->var.bits_per_pixel == 8) { | ||
1046 | if (cmap->start + cmap->len > info->cmap.start + | ||
1047 | info->cmap.len || cmap->start < info->cmap.start) | ||
1048 | return -EINVAL; | ||
1049 | |||
1050 | entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); | ||
1051 | if (!entries) | ||
1052 | return -ENOMEM; | ||
1053 | |||
1054 | for (i = 0; i < cmap->len; i++) { | ||
1055 | entries[i].red = cmap->red[i] >> shift; | ||
1056 | entries[i].green = cmap->green[i] >> shift; | ||
1057 | entries[i].blue = cmap->blue[i] >> shift; | ||
1058 | entries[i].pad = 0; | ||
1059 | } | ||
1060 | err = uvesafb_setpalette(entries, cmap->len, cmap->start, info); | ||
1061 | kfree(entries); | ||
1062 | } else { | ||
1063 | /* | ||
1064 | * For modes with bpp > 8, we only set the pseudo palette in | ||
1065 | * the fb_info struct. We rely on uvesafb_setcolreg to do all | ||
1066 | * sanity checking. | ||
1067 | */ | ||
1068 | for (i = 0; i < cmap->len; i++) { | ||
1069 | err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i], | ||
1070 | cmap->green[i], cmap->blue[i], | ||
1071 | 0, info); | ||
1072 | } | ||
1073 | } | ||
1074 | return err; | ||
1075 | } | ||
1076 | |||
1077 | static int uvesafb_pan_display(struct fb_var_screeninfo *var, | ||
1078 | struct fb_info *info) | ||
1079 | { | ||
1080 | #ifdef CONFIG_X86_32 | ||
1081 | int offset; | ||
1082 | struct uvesafb_par *par = info->par; | ||
1083 | |||
1084 | offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; | ||
1085 | |||
1086 | /* | ||
1087 | * It turns out it's not the best idea to do panning via vm86, | ||
1088 | * so we only allow it if we have a PMI. | ||
1089 | */ | ||
1090 | if (par->pmi_start) { | ||
1091 | __asm__ __volatile__( | ||
1092 | "call *(%%edi)" | ||
1093 | : /* no return value */ | ||
1094 | : "a" (0x4f07), /* EAX */ | ||
1095 | "b" (0), /* EBX */ | ||
1096 | "c" (offset), /* ECX */ | ||
1097 | "d" (offset >> 16), /* EDX */ | ||
1098 | "D" (&par->pmi_start)); /* EDI */ | ||
1099 | } | ||
1100 | #endif | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int uvesafb_blank(int blank, struct fb_info *info) | ||
1105 | { | ||
1106 | struct uvesafb_par *par = info->par; | ||
1107 | struct uvesafb_ktask *task; | ||
1108 | int err = 1; | ||
1109 | |||
1110 | #ifdef CONFIG_X86 | ||
1111 | if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) { | ||
1112 | int loop = 10000; | ||
1113 | u8 seq = 0, crtc17 = 0; | ||
1114 | |||
1115 | if (blank == FB_BLANK_POWERDOWN) { | ||
1116 | seq = 0x20; | ||
1117 | crtc17 = 0x00; | ||
1118 | err = 0; | ||
1119 | } else { | ||
1120 | seq = 0x00; | ||
1121 | crtc17 = 0x80; | ||
1122 | err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL; | ||
1123 | } | ||
1124 | |||
1125 | vga_wseq(NULL, 0x00, 0x01); | ||
1126 | seq |= vga_rseq(NULL, 0x01) & ~0x20; | ||
1127 | vga_wseq(NULL, 0x00, seq); | ||
1128 | |||
1129 | crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80; | ||
1130 | while (loop--); | ||
1131 | vga_wcrt(NULL, 0x17, crtc17); | ||
1132 | vga_wseq(NULL, 0x00, 0x03); | ||
1133 | } else | ||
1134 | #endif /* CONFIG_X86 */ | ||
1135 | { | ||
1136 | task = uvesafb_prep(); | ||
1137 | if (!task) | ||
1138 | return -ENOMEM; | ||
1139 | |||
1140 | task->t.regs.eax = 0x4f10; | ||
1141 | switch (blank) { | ||
1142 | case FB_BLANK_UNBLANK: | ||
1143 | task->t.regs.ebx = 0x0001; | ||
1144 | break; | ||
1145 | case FB_BLANK_NORMAL: | ||
1146 | task->t.regs.ebx = 0x0101; /* standby */ | ||
1147 | break; | ||
1148 | case FB_BLANK_POWERDOWN: | ||
1149 | task->t.regs.ebx = 0x0401; /* powerdown */ | ||
1150 | break; | ||
1151 | default: | ||
1152 | goto out; | ||
1153 | } | ||
1154 | |||
1155 | err = uvesafb_exec(task); | ||
1156 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) | ||
1157 | err = 1; | ||
1158 | out: uvesafb_free(task); | ||
1159 | } | ||
1160 | return err; | ||
1161 | } | ||
1162 | |||
1163 | static int uvesafb_open(struct fb_info *info, int user) | ||
1164 | { | ||
1165 | struct uvesafb_par *par = info->par; | ||
1166 | int cnt = atomic_read(&par->ref_count); | ||
1167 | |||
1168 | if (!cnt && par->vbe_state_size) | ||
1169 | par->vbe_state_orig = uvesafb_vbe_state_save(par); | ||
1170 | |||
1171 | atomic_inc(&par->ref_count); | ||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | static int uvesafb_release(struct fb_info *info, int user) | ||
1176 | { | ||
1177 | struct uvesafb_ktask *task = NULL; | ||
1178 | struct uvesafb_par *par = info->par; | ||
1179 | int cnt = atomic_read(&par->ref_count); | ||
1180 | |||
1181 | if (!cnt) | ||
1182 | return -EINVAL; | ||
1183 | |||
1184 | if (cnt != 1) | ||
1185 | goto out; | ||
1186 | |||
1187 | task = uvesafb_prep(); | ||
1188 | if (!task) | ||
1189 | goto out; | ||
1190 | |||
1191 | /* First, try to set the standard 80x25 text mode. */ | ||
1192 | task->t.regs.eax = 0x0003; | ||
1193 | uvesafb_exec(task); | ||
1194 | |||
1195 | /* | ||
1196 | * Now try to restore whatever hardware state we might have | ||
1197 | * saved when the fb device was first opened. | ||
1198 | */ | ||
1199 | uvesafb_vbe_state_restore(par, par->vbe_state_orig); | ||
1200 | out: | ||
1201 | atomic_dec(&par->ref_count); | ||
1202 | if (task) | ||
1203 | uvesafb_free(task); | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | static int uvesafb_set_par(struct fb_info *info) | ||
1208 | { | ||
1209 | struct uvesafb_par *par = info->par; | ||
1210 | struct uvesafb_ktask *task = NULL; | ||
1211 | struct vbe_crtc_ib *crtc = NULL; | ||
1212 | struct vbe_mode_ib *mode = NULL; | ||
1213 | int i, err = 0, depth = info->var.bits_per_pixel; | ||
1214 | |||
1215 | if (depth > 8 && depth != 32) | ||
1216 | depth = info->var.red.length + info->var.green.length + | ||
1217 | info->var.blue.length; | ||
1218 | |||
1219 | i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth, | ||
1220 | UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH); | ||
1221 | if (i >= 0) | ||
1222 | mode = &par->vbe_modes[i]; | ||
1223 | else | ||
1224 | return -EINVAL; | ||
1225 | |||
1226 | task = uvesafb_prep(); | ||
1227 | if (!task) | ||
1228 | return -ENOMEM; | ||
1229 | setmode: | ||
1230 | task->t.regs.eax = 0x4f02; | ||
1231 | task->t.regs.ebx = mode->mode_id | 0x4000; /* use LFB */ | ||
1232 | |||
1233 | if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc && | ||
1234 | info->var.pixclock != 0) { | ||
1235 | task->t.regs.ebx |= 0x0800; /* use CRTC data */ | ||
1236 | task->t.flags = TF_BUF_ESDI; | ||
1237 | crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL); | ||
1238 | if (!crtc) { | ||
1239 | err = -ENOMEM; | ||
1240 | goto out; | ||
1241 | } | ||
1242 | crtc->horiz_start = info->var.xres + info->var.right_margin; | ||
1243 | crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; | ||
1244 | crtc->horiz_total = crtc->horiz_end + info->var.left_margin; | ||
1245 | |||
1246 | crtc->vert_start = info->var.yres + info->var.lower_margin; | ||
1247 | crtc->vert_end = crtc->vert_start + info->var.vsync_len; | ||
1248 | crtc->vert_total = crtc->vert_end + info->var.upper_margin; | ||
1249 | |||
1250 | crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000; | ||
1251 | crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock / | ||
1252 | (crtc->vert_total * crtc->horiz_total))); | ||
1253 | |||
1254 | if (info->var.vmode & FB_VMODE_DOUBLE) | ||
1255 | crtc->flags |= 0x1; | ||
1256 | if (info->var.vmode & FB_VMODE_INTERLACED) | ||
1257 | crtc->flags |= 0x2; | ||
1258 | if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) | ||
1259 | crtc->flags |= 0x4; | ||
1260 | if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) | ||
1261 | crtc->flags |= 0x8; | ||
1262 | memcpy(&par->crtc, crtc, sizeof(*crtc)); | ||
1263 | } else { | ||
1264 | memset(&par->crtc, 0, sizeof(*crtc)); | ||
1265 | } | ||
1266 | |||
1267 | task->t.buf_len = sizeof(struct vbe_crtc_ib); | ||
1268 | task->buf = &par->crtc; | ||
1269 | |||
1270 | err = uvesafb_exec(task); | ||
1271 | if (err || (task->t.regs.eax & 0xffff) != 0x004f) { | ||
1272 | /* | ||
1273 | * The mode switch might have failed because we tried to | ||
1274 | * use our own timings. Try again with the default timings. | ||
1275 | */ | ||
1276 | if (crtc != NULL) { | ||
1277 | printk(KERN_WARNING "uvesafb: mode switch failed " | ||
1278 | "(eax=0x%x, err=%d). Trying again with " | ||
1279 | "default timings.\n", task->t.regs.eax, err); | ||
1280 | uvesafb_reset(task); | ||
1281 | kfree(crtc); | ||
1282 | crtc = NULL; | ||
1283 | info->var.pixclock = 0; | ||
1284 | goto setmode; | ||
1285 | } else { | ||
1286 | printk(KERN_ERR "uvesafb: mode switch failed (eax=" | ||
1287 | "0x%x, err=%d)\n", task->t.regs.eax, err); | ||
1288 | err = -EINVAL; | ||
1289 | goto out; | ||
1290 | } | ||
1291 | } | ||
1292 | par->mode_idx = i; | ||
1293 | |||
1294 | /* For 8bpp modes, always try to set the DAC to 8 bits. */ | ||
1295 | if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC && | ||
1296 | mode->bits_per_pixel <= 8) { | ||
1297 | uvesafb_reset(task); | ||
1298 | task->t.regs.eax = 0x4f08; | ||
1299 | task->t.regs.ebx = 0x0800; | ||
1300 | |||
1301 | err = uvesafb_exec(task); | ||
1302 | if (err || (task->t.regs.eax & 0xffff) != 0x004f || | ||
1303 | ((task->t.regs.ebx & 0xff00) >> 8) != 8) { | ||
1304 | /* | ||
1305 | * We've failed to set the DAC palette format - | ||
1306 | * time to correct var. | ||
1307 | */ | ||
1308 | info->var.red.length = 6; | ||
1309 | info->var.green.length = 6; | ||
1310 | info->var.blue.length = 6; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | info->fix.visual = (info->var.bits_per_pixel == 8) ? | ||
1315 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
1316 | info->fix.line_length = mode->bytes_per_scan_line; | ||
1317 | |||
1318 | out: if (crtc != NULL) | ||
1319 | kfree(crtc); | ||
1320 | uvesafb_free(task); | ||
1321 | |||
1322 | return err; | ||
1323 | } | ||
1324 | |||
1325 | static void uvesafb_check_limits(struct fb_var_screeninfo *var, | ||
1326 | struct fb_info *info) | ||
1327 | { | ||
1328 | const struct fb_videomode *mode; | ||
1329 | struct uvesafb_par *par = info->par; | ||
1330 | |||
1331 | /* | ||
1332 | * If pixclock is set to 0, then we're using default BIOS timings | ||
1333 | * and thus don't have to perform any checks here. | ||
1334 | */ | ||
1335 | if (!var->pixclock) | ||
1336 | return; | ||
1337 | |||
1338 | if (par->vbe_ib.vbe_version < 0x0300) { | ||
1339 | fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info); | ||
1340 | return; | ||
1341 | } | ||
1342 | |||
1343 | if (!fb_validate_mode(var, info)) | ||
1344 | return; | ||
1345 | |||
1346 | mode = fb_find_best_mode(var, &info->modelist); | ||
1347 | if (mode) { | ||
1348 | if (mode->xres == var->xres && mode->yres == var->yres && | ||
1349 | !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) { | ||
1350 | fb_videomode_to_var(var, mode); | ||
1351 | return; | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1355 | if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) | ||
1356 | return; | ||
1357 | /* Use default refresh rate */ | ||
1358 | var->pixclock = 0; | ||
1359 | } | ||
1360 | |||
1361 | static int uvesafb_check_var(struct fb_var_screeninfo *var, | ||
1362 | struct fb_info *info) | ||
1363 | { | ||
1364 | struct uvesafb_par *par = info->par; | ||
1365 | struct vbe_mode_ib *mode = NULL; | ||
1366 | int match = -1; | ||
1367 | int depth = var->red.length + var->green.length + var->blue.length; | ||
1368 | |||
1369 | /* | ||
1370 | * Various apps will use bits_per_pixel to set the color depth, | ||
1371 | * which is theoretically incorrect, but which we'll try to handle | ||
1372 | * here. | ||
1373 | */ | ||
1374 | if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8) | ||
1375 | depth = var->bits_per_pixel; | ||
1376 | |||
1377 | match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth, | ||
1378 | UVESAFB_EXACT_RES); | ||
1379 | if (match == -1) | ||
1380 | return -EINVAL; | ||
1381 | |||
1382 | mode = &par->vbe_modes[match]; | ||
1383 | uvesafb_setup_var(var, info, mode); | ||
1384 | |||
1385 | /* | ||
1386 | * Check whether we have remapped enough memory for this mode. | ||
1387 | * We might be called at an early stage, when we haven't remapped | ||
1388 | * any memory yet, in which case we simply skip the check. | ||
1389 | */ | ||
1390 | if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len | ||
1391 | && info->fix.smem_len) | ||
1392 | return -EINVAL; | ||
1393 | |||
1394 | if ((var->vmode & FB_VMODE_DOUBLE) && | ||
1395 | !(par->vbe_modes[match].mode_attr & 0x100)) | ||
1396 | var->vmode &= ~FB_VMODE_DOUBLE; | ||
1397 | |||
1398 | if ((var->vmode & FB_VMODE_INTERLACED) && | ||
1399 | !(par->vbe_modes[match].mode_attr & 0x200)) | ||
1400 | var->vmode &= ~FB_VMODE_INTERLACED; | ||
1401 | |||
1402 | uvesafb_check_limits(var, info); | ||
1403 | |||
1404 | var->xres_virtual = var->xres; | ||
1405 | var->yres_virtual = (par->ypan) ? | ||
1406 | info->fix.smem_len / mode->bytes_per_scan_line : | ||
1407 | var->yres; | ||
1408 | return 0; | ||
1409 | } | ||
1410 | |||
1411 | static void uvesafb_save_state(struct fb_info *info) | ||
1412 | { | ||
1413 | struct uvesafb_par *par = info->par; | ||
1414 | |||
1415 | if (par->vbe_state_saved) | ||
1416 | kfree(par->vbe_state_saved); | ||
1417 | |||
1418 | par->vbe_state_saved = uvesafb_vbe_state_save(par); | ||
1419 | } | ||
1420 | |||
1421 | static void uvesafb_restore_state(struct fb_info *info) | ||
1422 | { | ||
1423 | struct uvesafb_par *par = info->par; | ||
1424 | |||
1425 | uvesafb_vbe_state_restore(par, par->vbe_state_saved); | ||
1426 | } | ||
1427 | |||
1428 | static struct fb_ops uvesafb_ops = { | ||
1429 | .owner = THIS_MODULE, | ||
1430 | .fb_open = uvesafb_open, | ||
1431 | .fb_release = uvesafb_release, | ||
1432 | .fb_setcolreg = uvesafb_setcolreg, | ||
1433 | .fb_setcmap = uvesafb_setcmap, | ||
1434 | .fb_pan_display = uvesafb_pan_display, | ||
1435 | .fb_blank = uvesafb_blank, | ||
1436 | .fb_fillrect = cfb_fillrect, | ||
1437 | .fb_copyarea = cfb_copyarea, | ||
1438 | .fb_imageblit = cfb_imageblit, | ||
1439 | .fb_check_var = uvesafb_check_var, | ||
1440 | .fb_set_par = uvesafb_set_par, | ||
1441 | .fb_save_state = uvesafb_save_state, | ||
1442 | .fb_restore_state = uvesafb_restore_state, | ||
1443 | }; | ||
1444 | |||
1445 | static void __devinit uvesafb_init_info(struct fb_info *info, | ||
1446 | struct vbe_mode_ib *mode) | ||
1447 | { | ||
1448 | unsigned int size_vmode; | ||
1449 | unsigned int size_remap; | ||
1450 | unsigned int size_total; | ||
1451 | struct uvesafb_par *par = info->par; | ||
1452 | int i, h; | ||
1453 | |||
1454 | info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par)); | ||
1455 | info->fix = uvesafb_fix; | ||
1456 | info->fix.ypanstep = par->ypan ? 1 : 0; | ||
1457 | info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0; | ||
1458 | |||
1459 | /* | ||
1460 | * If we were unable to get the state buffer size, disable | ||
1461 | * functions for saving and restoring the hardware state. | ||
1462 | */ | ||
1463 | if (par->vbe_state_size == 0) { | ||
1464 | info->fbops->fb_save_state = NULL; | ||
1465 | info->fbops->fb_restore_state = NULL; | ||
1466 | } | ||
1467 | |||
1468 | /* Disable blanking if the user requested so. */ | ||
1469 | if (!blank) | ||
1470 | info->fbops->fb_blank = NULL; | ||
1471 | |||
1472 | /* | ||
1473 | * Find out how much IO memory is required for the mode with | ||
1474 | * the highest resolution. | ||
1475 | */ | ||
1476 | size_remap = 0; | ||
1477 | for (i = 0; i < par->vbe_modes_cnt; i++) { | ||
1478 | h = par->vbe_modes[i].bytes_per_scan_line * | ||
1479 | par->vbe_modes[i].y_res; | ||
1480 | if (h > size_remap) | ||
1481 | size_remap = h; | ||
1482 | } | ||
1483 | size_remap *= 2; | ||
1484 | |||
1485 | /* | ||
1486 | * size_vmode -- that is the amount of memory needed for the | ||
1487 | * used video mode, i.e. the minimum amount of | ||
1488 | * memory we need. | ||
1489 | */ | ||
1490 | if (mode != NULL) { | ||
1491 | size_vmode = info->var.yres * mode->bytes_per_scan_line; | ||
1492 | } else { | ||
1493 | size_vmode = info->var.yres * info->var.xres * | ||
1494 | ((info->var.bits_per_pixel + 7) >> 3); | ||
1495 | } | ||
1496 | |||
1497 | /* | ||
1498 | * size_total -- all video memory we have. Used for mtrr | ||
1499 | * entries, resource allocation and bounds | ||
1500 | * checking. | ||
1501 | */ | ||
1502 | size_total = par->vbe_ib.total_memory * 65536; | ||
1503 | if (vram_total) | ||
1504 | size_total = vram_total * 1024 * 1024; | ||
1505 | if (size_total < size_vmode) | ||
1506 | size_total = size_vmode; | ||
1507 | |||
1508 | /* | ||
1509 | * size_remap -- the amount of video memory we are going to | ||
1510 | * use for vesafb. With modern cards it is no | ||
1511 | * option to simply use size_total as th | ||
1512 | * wastes plenty of kernel address space. | ||
1513 | */ | ||
1514 | if (vram_remap) | ||
1515 | size_remap = vram_remap * 1024 * 1024; | ||
1516 | if (size_remap < size_vmode) | ||
1517 | size_remap = size_vmode; | ||
1518 | if (size_remap > size_total) | ||
1519 | size_remap = size_total; | ||
1520 | |||
1521 | info->fix.smem_len = size_remap; | ||
1522 | info->fix.smem_start = mode->phys_base_ptr; | ||
1523 | |||
1524 | /* | ||
1525 | * We have to set yres_virtual here because when setup_var() was | ||
1526 | * called, smem_len wasn't defined yet. | ||
1527 | */ | ||
1528 | info->var.yres_virtual = info->fix.smem_len / | ||
1529 | mode->bytes_per_scan_line; | ||
1530 | |||
1531 | if (par->ypan && info->var.yres_virtual > info->var.yres) { | ||
1532 | printk(KERN_INFO "uvesafb: scrolling: %s " | ||
1533 | "using protected mode interface, " | ||
1534 | "yres_virtual=%d\n", | ||
1535 | (par->ypan > 1) ? "ywrap" : "ypan", | ||
1536 | info->var.yres_virtual); | ||
1537 | } else { | ||
1538 | printk(KERN_INFO "uvesafb: scrolling: redraw\n"); | ||
1539 | info->var.yres_virtual = info->var.yres; | ||
1540 | par->ypan = 0; | ||
1541 | } | ||
1542 | |||
1543 | info->flags = FBINFO_FLAG_DEFAULT | | ||
1544 | (par->ypan) ? FBINFO_HWACCEL_YPAN : 0; | ||
1545 | |||
1546 | if (!par->ypan) | ||
1547 | info->fbops->fb_pan_display = NULL; | ||
1548 | } | ||
1549 | |||
1550 | static void uvesafb_init_mtrr(struct fb_info *info) | ||
1551 | { | ||
1552 | #ifdef CONFIG_MTRR | ||
1553 | if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) { | ||
1554 | int temp_size = info->fix.smem_len; | ||
1555 | unsigned int type = 0; | ||
1556 | |||
1557 | switch (mtrr) { | ||
1558 | case 1: | ||
1559 | type = MTRR_TYPE_UNCACHABLE; | ||
1560 | break; | ||
1561 | case 2: | ||
1562 | type = MTRR_TYPE_WRBACK; | ||
1563 | break; | ||
1564 | case 3: | ||
1565 | type = MTRR_TYPE_WRCOMB; | ||
1566 | break; | ||
1567 | case 4: | ||
1568 | type = MTRR_TYPE_WRTHROUGH; | ||
1569 | break; | ||
1570 | default: | ||
1571 | type = 0; | ||
1572 | break; | ||
1573 | } | ||
1574 | |||
1575 | if (type) { | ||
1576 | int rc; | ||
1577 | |||
1578 | /* Find the largest power-of-two */ | ||
1579 | while (temp_size & (temp_size - 1)) | ||
1580 | temp_size &= (temp_size - 1); | ||
1581 | |||
1582 | /* Try and find a power of two to add */ | ||
1583 | do { | ||
1584 | rc = mtrr_add(info->fix.smem_start, | ||
1585 | temp_size, type, 1); | ||
1586 | temp_size >>= 1; | ||
1587 | } while (temp_size >= PAGE_SIZE && rc == -EINVAL); | ||
1588 | } | ||
1589 | } | ||
1590 | #endif /* CONFIG_MTRR */ | ||
1591 | } | ||
1592 | |||
1593 | |||
1594 | static ssize_t uvesafb_show_vbe_ver(struct device *dev, | ||
1595 | struct device_attribute *attr, char *buf) | ||
1596 | { | ||
1597 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1598 | struct uvesafb_par *par = info->par; | ||
1599 | |||
1600 | return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version); | ||
1601 | } | ||
1602 | |||
1603 | static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL); | ||
1604 | |||
1605 | static ssize_t uvesafb_show_vbe_modes(struct device *dev, | ||
1606 | struct device_attribute *attr, char *buf) | ||
1607 | { | ||
1608 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1609 | struct uvesafb_par *par = info->par; | ||
1610 | int ret = 0, i; | ||
1611 | |||
1612 | for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) { | ||
1613 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1614 | "%dx%d-%d, 0x%.4x\n", | ||
1615 | par->vbe_modes[i].x_res, par->vbe_modes[i].y_res, | ||
1616 | par->vbe_modes[i].depth, par->vbe_modes[i].mode_id); | ||
1617 | } | ||
1618 | |||
1619 | return ret; | ||
1620 | } | ||
1621 | |||
1622 | static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL); | ||
1623 | |||
1624 | static ssize_t uvesafb_show_vendor(struct device *dev, | ||
1625 | struct device_attribute *attr, char *buf) | ||
1626 | { | ||
1627 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1628 | struct uvesafb_par *par = info->par; | ||
1629 | |||
1630 | if (par->vbe_ib.oem_vendor_name_ptr) | ||
1631 | return snprintf(buf, PAGE_SIZE, "%s\n", (char *) | ||
1632 | (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr); | ||
1633 | else | ||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1637 | static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL); | ||
1638 | |||
1639 | static ssize_t uvesafb_show_product_name(struct device *dev, | ||
1640 | struct device_attribute *attr, char *buf) | ||
1641 | { | ||
1642 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1643 | struct uvesafb_par *par = info->par; | ||
1644 | |||
1645 | if (par->vbe_ib.oem_product_name_ptr) | ||
1646 | return snprintf(buf, PAGE_SIZE, "%s\n", (char *) | ||
1647 | (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr); | ||
1648 | else | ||
1649 | return 0; | ||
1650 | } | ||
1651 | |||
1652 | static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL); | ||
1653 | |||
1654 | static ssize_t uvesafb_show_product_rev(struct device *dev, | ||
1655 | struct device_attribute *attr, char *buf) | ||
1656 | { | ||
1657 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1658 | struct uvesafb_par *par = info->par; | ||
1659 | |||
1660 | if (par->vbe_ib.oem_product_rev_ptr) | ||
1661 | return snprintf(buf, PAGE_SIZE, "%s\n", (char *) | ||
1662 | (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr); | ||
1663 | else | ||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL); | ||
1668 | |||
1669 | static ssize_t uvesafb_show_oem_string(struct device *dev, | ||
1670 | struct device_attribute *attr, char *buf) | ||
1671 | { | ||
1672 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1673 | struct uvesafb_par *par = info->par; | ||
1674 | |||
1675 | if (par->vbe_ib.oem_string_ptr) | ||
1676 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
1677 | (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr); | ||
1678 | else | ||
1679 | return 0; | ||
1680 | } | ||
1681 | |||
1682 | static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL); | ||
1683 | |||
1684 | static ssize_t uvesafb_show_nocrtc(struct device *dev, | ||
1685 | struct device_attribute *attr, char *buf) | ||
1686 | { | ||
1687 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1688 | struct uvesafb_par *par = info->par; | ||
1689 | |||
1690 | return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc); | ||
1691 | } | ||
1692 | |||
1693 | static ssize_t uvesafb_store_nocrtc(struct device *dev, | ||
1694 | struct device_attribute *attr, const char *buf, size_t count) | ||
1695 | { | ||
1696 | struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); | ||
1697 | struct uvesafb_par *par = info->par; | ||
1698 | |||
1699 | if (count > 0) { | ||
1700 | if (buf[0] == '0') | ||
1701 | par->nocrtc = 0; | ||
1702 | else | ||
1703 | par->nocrtc = 1; | ||
1704 | } | ||
1705 | return count; | ||
1706 | } | ||
1707 | |||
1708 | static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc, | ||
1709 | uvesafb_store_nocrtc); | ||
1710 | |||
1711 | static struct attribute *uvesafb_dev_attrs[] = { | ||
1712 | &dev_attr_vbe_version.attr, | ||
1713 | &dev_attr_vbe_modes.attr, | ||
1714 | &dev_attr_oem_vendor.attr, | ||
1715 | &dev_attr_oem_product_name.attr, | ||
1716 | &dev_attr_oem_product_rev.attr, | ||
1717 | &dev_attr_oem_string.attr, | ||
1718 | &dev_attr_nocrtc.attr, | ||
1719 | NULL, | ||
1720 | }; | ||
1721 | |||
1722 | static struct attribute_group uvesafb_dev_attgrp = { | ||
1723 | .name = NULL, | ||
1724 | .attrs = uvesafb_dev_attrs, | ||
1725 | }; | ||
1726 | |||
1727 | static int __devinit uvesafb_probe(struct platform_device *dev) | ||
1728 | { | ||
1729 | struct fb_info *info; | ||
1730 | struct vbe_mode_ib *mode = NULL; | ||
1731 | struct uvesafb_par *par; | ||
1732 | int err = 0, i; | ||
1733 | |||
1734 | info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev); | ||
1735 | if (!info) | ||
1736 | return -ENOMEM; | ||
1737 | |||
1738 | par = info->par; | ||
1739 | |||
1740 | err = uvesafb_vbe_init(info); | ||
1741 | if (err) { | ||
1742 | printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err); | ||
1743 | goto out; | ||
1744 | } | ||
1745 | |||
1746 | info->fbops = &uvesafb_ops; | ||
1747 | |||
1748 | i = uvesafb_vbe_init_mode(info); | ||
1749 | if (i < 0) { | ||
1750 | err = -EINVAL; | ||
1751 | goto out; | ||
1752 | } else { | ||
1753 | mode = &par->vbe_modes[i]; | ||
1754 | } | ||
1755 | |||
1756 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | ||
1757 | err = -ENXIO; | ||
1758 | goto out; | ||
1759 | } | ||
1760 | |||
1761 | uvesafb_init_info(info, mode); | ||
1762 | |||
1763 | if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, | ||
1764 | "uvesafb")) { | ||
1765 | printk(KERN_ERR "uvesafb: cannot reserve video memory at " | ||
1766 | "0x%lx\n", info->fix.smem_start); | ||
1767 | err = -EIO; | ||
1768 | goto out_mode; | ||
1769 | } | ||
1770 | |||
1771 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); | ||
1772 | |||
1773 | if (!info->screen_base) { | ||
1774 | printk(KERN_ERR | ||
1775 | "uvesafb: abort, cannot ioremap 0x%x bytes of video " | ||
1776 | "memory at 0x%lx\n", | ||
1777 | info->fix.smem_len, info->fix.smem_start); | ||
1778 | err = -EIO; | ||
1779 | goto out_mem; | ||
1780 | } | ||
1781 | |||
1782 | if (!request_region(0x3c0, 32, "uvesafb")) { | ||
1783 | printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n"); | ||
1784 | err = -EIO; | ||
1785 | goto out_unmap; | ||
1786 | } | ||
1787 | |||
1788 | uvesafb_init_mtrr(info); | ||
1789 | platform_set_drvdata(dev, info); | ||
1790 | |||
1791 | if (register_framebuffer(info) < 0) { | ||
1792 | printk(KERN_ERR | ||
1793 | "uvesafb: failed to register framebuffer device\n"); | ||
1794 | err = -EINVAL; | ||
1795 | goto out_reg; | ||
1796 | } | ||
1797 | |||
1798 | printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, " | ||
1799 | "using %dk, total %dk\n", info->fix.smem_start, | ||
1800 | info->screen_base, info->fix.smem_len/1024, | ||
1801 | par->vbe_ib.total_memory * 64); | ||
1802 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
1803 | info->fix.id); | ||
1804 | |||
1805 | err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp); | ||
1806 | if (err != 0) | ||
1807 | printk(KERN_WARNING "fb%d: failed to register attributes\n", | ||
1808 | info->node); | ||
1809 | |||
1810 | return 0; | ||
1811 | |||
1812 | out_reg: | ||
1813 | release_region(0x3c0, 32); | ||
1814 | out_unmap: | ||
1815 | iounmap(info->screen_base); | ||
1816 | out_mem: | ||
1817 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
1818 | out_mode: | ||
1819 | if (!list_empty(&info->modelist)) | ||
1820 | fb_destroy_modelist(&info->modelist); | ||
1821 | fb_destroy_modedb(info->monspecs.modedb); | ||
1822 | fb_dealloc_cmap(&info->cmap); | ||
1823 | out: | ||
1824 | if (par->vbe_modes) | ||
1825 | kfree(par->vbe_modes); | ||
1826 | |||
1827 | framebuffer_release(info); | ||
1828 | return err; | ||
1829 | } | ||
1830 | |||
1831 | static int uvesafb_remove(struct platform_device *dev) | ||
1832 | { | ||
1833 | struct fb_info *info = platform_get_drvdata(dev); | ||
1834 | |||
1835 | if (info) { | ||
1836 | struct uvesafb_par *par = info->par; | ||
1837 | |||
1838 | sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp); | ||
1839 | unregister_framebuffer(info); | ||
1840 | release_region(0x3c0, 32); | ||
1841 | iounmap(info->screen_base); | ||
1842 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
1843 | fb_destroy_modedb(info->monspecs.modedb); | ||
1844 | fb_dealloc_cmap(&info->cmap); | ||
1845 | |||
1846 | if (par) { | ||
1847 | if (par->vbe_modes) | ||
1848 | kfree(par->vbe_modes); | ||
1849 | if (par->vbe_state_orig) | ||
1850 | kfree(par->vbe_state_orig); | ||
1851 | if (par->vbe_state_saved) | ||
1852 | kfree(par->vbe_state_saved); | ||
1853 | } | ||
1854 | |||
1855 | framebuffer_release(info); | ||
1856 | } | ||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | static struct platform_driver uvesafb_driver = { | ||
1861 | .probe = uvesafb_probe, | ||
1862 | .remove = uvesafb_remove, | ||
1863 | .driver = { | ||
1864 | .name = "uvesafb", | ||
1865 | }, | ||
1866 | }; | ||
1867 | |||
1868 | static struct platform_device *uvesafb_device; | ||
1869 | |||
1870 | #ifndef MODULE | ||
1871 | static int __devinit uvesafb_setup(char *options) | ||
1872 | { | ||
1873 | char *this_opt; | ||
1874 | |||
1875 | if (!options || !*options) | ||
1876 | return 0; | ||
1877 | |||
1878 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
1879 | if (!*this_opt) continue; | ||
1880 | |||
1881 | if (!strcmp(this_opt, "redraw")) | ||
1882 | ypan = 0; | ||
1883 | else if (!strcmp(this_opt, "ypan")) | ||
1884 | ypan = 1; | ||
1885 | else if (!strcmp(this_opt, "ywrap")) | ||
1886 | ypan = 2; | ||
1887 | else if (!strcmp(this_opt, "vgapal")) | ||
1888 | pmi_setpal = 0; | ||
1889 | else if (!strcmp(this_opt, "pmipal")) | ||
1890 | pmi_setpal = 1; | ||
1891 | else if (!strncmp(this_opt, "mtrr:", 5)) | ||
1892 | mtrr = simple_strtoul(this_opt+5, NULL, 0); | ||
1893 | else if (!strcmp(this_opt, "nomtrr")) | ||
1894 | mtrr = 0; | ||
1895 | else if (!strcmp(this_opt, "nocrtc")) | ||
1896 | nocrtc = 1; | ||
1897 | else if (!strcmp(this_opt, "noedid")) | ||
1898 | noedid = 1; | ||
1899 | else if (!strcmp(this_opt, "noblank")) | ||
1900 | blank = 0; | ||
1901 | else if (!strncmp(this_opt, "vtotal:", 7)) | ||
1902 | vram_total = simple_strtoul(this_opt + 7, NULL, 0); | ||
1903 | else if (!strncmp(this_opt, "vremap:", 7)) | ||
1904 | vram_remap = simple_strtoul(this_opt + 7, NULL, 0); | ||
1905 | else if (!strncmp(this_opt, "maxhf:", 6)) | ||
1906 | maxhf = simple_strtoul(this_opt + 6, NULL, 0); | ||
1907 | else if (!strncmp(this_opt, "maxvf:", 6)) | ||
1908 | maxvf = simple_strtoul(this_opt + 6, NULL, 0); | ||
1909 | else if (!strncmp(this_opt, "maxclk:", 7)) | ||
1910 | maxclk = simple_strtoul(this_opt + 7, NULL, 0); | ||
1911 | else if (!strncmp(this_opt, "vbemode:", 8)) | ||
1912 | vbemode = simple_strtoul(this_opt + 8, NULL, 0); | ||
1913 | else if (this_opt[0] >= '0' && this_opt[0] <= '9') { | ||
1914 | mode_option = this_opt; | ||
1915 | } else { | ||
1916 | printk(KERN_WARNING | ||
1917 | "uvesafb: unrecognized option %s\n", this_opt); | ||
1918 | } | ||
1919 | } | ||
1920 | |||
1921 | return 0; | ||
1922 | } | ||
1923 | #endif /* !MODULE */ | ||
1924 | |||
1925 | static ssize_t show_v86d(struct device_driver *dev, char *buf) | ||
1926 | { | ||
1927 | return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path); | ||
1928 | } | ||
1929 | |||
1930 | static ssize_t store_v86d(struct device_driver *dev, const char *buf, | ||
1931 | size_t count) | ||
1932 | { | ||
1933 | strncpy(v86d_path, buf, PATH_MAX); | ||
1934 | return count; | ||
1935 | } | ||
1936 | |||
1937 | static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d); | ||
1938 | |||
1939 | static int __devinit uvesafb_init(void) | ||
1940 | { | ||
1941 | int err; | ||
1942 | |||
1943 | #ifndef MODULE | ||
1944 | char *option = NULL; | ||
1945 | |||
1946 | if (fb_get_options("uvesafb", &option)) | ||
1947 | return -ENODEV; | ||
1948 | uvesafb_setup(option); | ||
1949 | #endif | ||
1950 | err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback); | ||
1951 | if (err) | ||
1952 | return err; | ||
1953 | |||
1954 | err = platform_driver_register(&uvesafb_driver); | ||
1955 | |||
1956 | if (!err) { | ||
1957 | uvesafb_device = platform_device_alloc("uvesafb", 0); | ||
1958 | if (uvesafb_device) | ||
1959 | err = platform_device_add(uvesafb_device); | ||
1960 | else | ||
1961 | err = -ENOMEM; | ||
1962 | |||
1963 | if (err) { | ||
1964 | platform_device_put(uvesafb_device); | ||
1965 | platform_driver_unregister(&uvesafb_driver); | ||
1966 | cn_del_callback(&uvesafb_cn_id); | ||
1967 | return err; | ||
1968 | } | ||
1969 | |||
1970 | err = driver_create_file(&uvesafb_driver.driver, | ||
1971 | &driver_attr_v86d); | ||
1972 | if (err) { | ||
1973 | printk(KERN_WARNING "uvesafb: failed to register " | ||
1974 | "attributes\n"); | ||
1975 | err = 0; | ||
1976 | } | ||
1977 | } | ||
1978 | return err; | ||
1979 | } | ||
1980 | |||
1981 | module_init(uvesafb_init); | ||
1982 | |||
1983 | static void __devexit uvesafb_exit(void) | ||
1984 | { | ||
1985 | struct uvesafb_ktask *task; | ||
1986 | |||
1987 | if (v86d_started) { | ||
1988 | task = uvesafb_prep(); | ||
1989 | if (task) { | ||
1990 | task->t.flags = TF_EXIT; | ||
1991 | uvesafb_exec(task); | ||
1992 | uvesafb_free(task); | ||
1993 | } | ||
1994 | } | ||
1995 | |||
1996 | cn_del_callback(&uvesafb_cn_id); | ||
1997 | driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d); | ||
1998 | platform_device_unregister(uvesafb_device); | ||
1999 | platform_driver_unregister(&uvesafb_driver); | ||
2000 | } | ||
2001 | |||
2002 | module_exit(uvesafb_exit); | ||
2003 | |||
2004 | static inline int param_get_scroll(char *buffer, struct kernel_param *kp) | ||
2005 | { | ||
2006 | return 0; | ||
2007 | } | ||
2008 | |||
2009 | static inline int param_set_scroll(const char *val, struct kernel_param *kp) | ||
2010 | { | ||
2011 | ypan = 0; | ||
2012 | |||
2013 | if (!strcmp(val, "redraw")) | ||
2014 | ypan = 0; | ||
2015 | else if (!strcmp(val, "ypan")) | ||
2016 | ypan = 1; | ||
2017 | else if (!strcmp(val, "ywrap")) | ||
2018 | ypan = 2; | ||
2019 | |||
2020 | return 0; | ||
2021 | } | ||
2022 | |||
2023 | #define param_check_scroll(name, p) __param_check(name, p, void); | ||
2024 | |||
2025 | module_param_named(scroll, ypan, scroll, 0); | ||
2026 | MODULE_PARM_DESC(scroll, | ||
2027 | "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'"); | ||
2028 | module_param_named(vgapal, pmi_setpal, invbool, 0); | ||
2029 | MODULE_PARM_DESC(vgapal, "Set palette using VGA registers"); | ||
2030 | module_param_named(pmipal, pmi_setpal, bool, 0); | ||
2031 | MODULE_PARM_DESC(pmipal, "Set palette using PMI calls"); | ||
2032 | module_param(mtrr, uint, 0); | ||
2033 | MODULE_PARM_DESC(mtrr, | ||
2034 | "Memory Type Range Registers setting. Use 0 to disable."); | ||
2035 | module_param(blank, bool, 0); | ||
2036 | MODULE_PARM_DESC(blank, "Enable hardware blanking"); | ||
2037 | module_param(nocrtc, bool, 0); | ||
2038 | MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes"); | ||
2039 | module_param(noedid, bool, 0); | ||
2040 | MODULE_PARM_DESC(noedid, | ||
2041 | "Ignore EDID-provided monitor limits when setting modes"); | ||
2042 | module_param(vram_remap, uint, 0); | ||
2043 | MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]"); | ||
2044 | module_param(vram_total, uint, 0); | ||
2045 | MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]"); | ||
2046 | module_param(maxclk, ushort, 0); | ||
2047 | MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data"); | ||
2048 | module_param(maxhf, ushort, 0); | ||
2049 | MODULE_PARM_DESC(maxhf, | ||
2050 | "Maximum horizontal frequency [kHz], overrides EDID data"); | ||
2051 | module_param(maxvf, ushort, 0); | ||
2052 | MODULE_PARM_DESC(maxvf, | ||
2053 | "Maximum vertical frequency [Hz], overrides EDID data"); | ||
2054 | module_param_named(mode, mode_option, charp, 0); | ||
2055 | MODULE_PARM_DESC(mode, | ||
2056 | "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); | ||
2057 | module_param(vbemode, ushort, 0); | ||
2058 | MODULE_PARM_DESC(vbemode, | ||
2059 | "VBE mode number to set, overrides the 'mode' option"); | ||
2060 | module_param_string(v86d, v86d_path, PATH_MAX, 0660); | ||
2061 | MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper."); | ||
2062 | |||
2063 | MODULE_LICENSE("GPL"); | ||
2064 | MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>"); | ||
2065 | MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards"); | ||
2066 | |||
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index de531c907718..ff9e805c43bc 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/cacheflush.h> | 39 | #include <asm/cacheflush.h> |
40 | #include <asm/tlbflush.h> | 40 | #include <asm/tlbflush.h> |
41 | #include <linux/mmzone.h> | 41 | #include <linux/mmzone.h> |
42 | #include <asm/uaccess.h> | ||
43 | 42 | ||
44 | /* #define VERMILION_DEBUG */ | 43 | /* #define VERMILION_DEBUG */ |
45 | 44 | ||
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 64ee78c3c12b..072638a9528a 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | 23 | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <linux/fb.h> | 24 | #include <linux/fb.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | 26 | ||
@@ -38,6 +37,48 @@ static void *videomemory; | |||
38 | static u_long videomemorysize = VIDEOMEMSIZE; | 37 | static u_long videomemorysize = VIDEOMEMSIZE; |
39 | module_param(videomemorysize, ulong, 0); | 38 | module_param(videomemorysize, ulong, 0); |
40 | 39 | ||
40 | /********************************************************************** | ||
41 | * | ||
42 | * Memory management | ||
43 | * | ||
44 | **********************************************************************/ | ||
45 | static void *rvmalloc(unsigned long size) | ||
46 | { | ||
47 | void *mem; | ||
48 | unsigned long adr; | ||
49 | |||
50 | size = PAGE_ALIGN(size); | ||
51 | mem = vmalloc_32(size); | ||
52 | if (!mem) | ||
53 | return NULL; | ||
54 | |||
55 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
56 | adr = (unsigned long) mem; | ||
57 | while (size > 0) { | ||
58 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
59 | adr += PAGE_SIZE; | ||
60 | size -= PAGE_SIZE; | ||
61 | } | ||
62 | |||
63 | return mem; | ||
64 | } | ||
65 | |||
66 | static void rvfree(void *mem, unsigned long size) | ||
67 | { | ||
68 | unsigned long adr; | ||
69 | |||
70 | if (!mem) | ||
71 | return; | ||
72 | |||
73 | adr = (unsigned long) mem; | ||
74 | while ((long) size > 0) { | ||
75 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
76 | adr += PAGE_SIZE; | ||
77 | size -= PAGE_SIZE; | ||
78 | } | ||
79 | vfree(mem); | ||
80 | } | ||
81 | |||
41 | static struct fb_var_screeninfo vfb_default __initdata = { | 82 | static struct fb_var_screeninfo vfb_default __initdata = { |
42 | .xres = 640, | 83 | .xres = 640, |
43 | .yres = 480, | 84 | .yres = 480, |
@@ -372,7 +413,33 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, | |||
372 | static int vfb_mmap(struct fb_info *info, | 413 | static int vfb_mmap(struct fb_info *info, |
373 | struct vm_area_struct *vma) | 414 | struct vm_area_struct *vma) |
374 | { | 415 | { |
375 | return -EINVAL; | 416 | unsigned long start = vma->vm_start; |
417 | unsigned long size = vma->vm_end - vma->vm_start; | ||
418 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
419 | unsigned long page, pos; | ||
420 | |||
421 | if (offset + size > info->fix.smem_len) { | ||
422 | return -EINVAL; | ||
423 | } | ||
424 | |||
425 | pos = (unsigned long)info->fix.smem_start + offset; | ||
426 | |||
427 | while (size > 0) { | ||
428 | page = vmalloc_to_pfn((void *)pos); | ||
429 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
430 | return -EAGAIN; | ||
431 | } | ||
432 | start += PAGE_SIZE; | ||
433 | pos += PAGE_SIZE; | ||
434 | if (size > PAGE_SIZE) | ||
435 | size -= PAGE_SIZE; | ||
436 | else | ||
437 | size = 0; | ||
438 | } | ||
439 | |||
440 | vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ | ||
441 | return 0; | ||
442 | |||
376 | } | 443 | } |
377 | 444 | ||
378 | #ifndef MODULE | 445 | #ifndef MODULE |
@@ -407,7 +474,7 @@ static int __init vfb_probe(struct platform_device *dev) | |||
407 | /* | 474 | /* |
408 | * For real video cards we use ioremap. | 475 | * For real video cards we use ioremap. |
409 | */ | 476 | */ |
410 | if (!(videomemory = vmalloc(videomemorysize))) | 477 | if (!(videomemory = rvmalloc(videomemorysize))) |
411 | return retval; | 478 | return retval; |
412 | 479 | ||
413 | /* | 480 | /* |
@@ -430,6 +497,8 @@ static int __init vfb_probe(struct platform_device *dev) | |||
430 | 497 | ||
431 | if (!retval || (retval == 4)) | 498 | if (!retval || (retval == 4)) |
432 | info->var = vfb_default; | 499 | info->var = vfb_default; |
500 | vfb_fix.smem_start = (unsigned long) videomemory; | ||
501 | vfb_fix.smem_len = videomemorysize; | ||
433 | info->fix = vfb_fix; | 502 | info->fix = vfb_fix; |
434 | info->pseudo_palette = info->par; | 503 | info->pseudo_palette = info->par; |
435 | info->par = NULL; | 504 | info->par = NULL; |
@@ -453,7 +522,7 @@ err2: | |||
453 | err1: | 522 | err1: |
454 | framebuffer_release(info); | 523 | framebuffer_release(info); |
455 | err: | 524 | err: |
456 | vfree(videomemory); | 525 | rvfree(videomemory, videomemorysize); |
457 | return retval; | 526 | return retval; |
458 | } | 527 | } |
459 | 528 | ||
@@ -463,7 +532,7 @@ static int vfb_remove(struct platform_device *dev) | |||
463 | 532 | ||
464 | if (info) { | 533 | if (info) { |
465 | unregister_framebuffer(info); | 534 | unregister_framebuffer(info); |
466 | vfree(videomemory); | 535 | rvfree(videomemory, videomemorysize); |
467 | framebuffer_release(info); | 536 | framebuffer_release(info); |
468 | } | 537 | } |
469 | return 0; | 538 | return 0; |