From 22098763a10d9c1340827fcf6edab66f153b27f0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 13 Sep 2026 12:27:00 -0700 Subject: Merge tag 'trace-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing fixes from Steven Rostedt: - Don't destroy user event fields when removal fails User event fields are destroyed before the event is removed from visibility. But that can fail leaving the still visible event with no fields. Move the destroying of the fields to after the event is successfully removed from visibility. - Initialize function graph state is fork before calling copy_exec_state() For non-CLONE_VM forks, copy_exec_state() allocates a new task_exec_state. If that allocation fails, ftrace_graph_exit_task() will free the tasks ret_stack pointer. Since that pointer is still using the parent's ret_stack, it mistakenly frees the parent's pointer too. Call ftrace_graph_init() on the task first which will NULL out the new tasks's ret_stack and if the copy fails, it will not free anything. - Remove FGRAPH_MAX_INDEX The macro FGRAPH_MAX_INDEX was added but never used. Remove it. - Save ent_size in function graph printing of nested functions The function graph tracer needs to look at the next event to see if the next event is the return of the current function entry. If it is, it prints a single line: ktime_get(); Otherwise it prints it like a nested function: tick_nohz_irq_exit() { ktime_get(); kcpustat_irq_exit(); } In order to look at the next event, it must save the current event so that it has the information to print from it. It saves the event in the iterator descriptor called "ent". What it doesn't save is the ent_size of the event which is now used to know if the function graph arguments are to be printed. The peek doesn't save the size so the size used happens to be that of the size of the last event that was seen. Save the entry event size in the iterator descriptor so that the correct size is used. - Fix several errors with freeing data in the histogram code The histogram code had a lot of leaked or or incorrect accounting when failures happen. Correct them. - Fix histogram regression of .percent and .graph modifiers Up until 6.3 histogram values could have "percent" or "graph" modifiers that changed how they were printed. But a change that added restricting histograms values from being strings, stack traces and other modifiers inadvertently prevented them from using the percent and graph modifiers, which were legal use cases for values. Put back the percent and graph modifiers. - Fix various typos in the comments - Set the trace_clock before initializing a histogram with clock argument The histogram API allows the user to specific which trace clock to use via a "clock=" string. The histogram is set up first before the clock is checked. If the passed in clock is not valid, it exits without fully fixing up the histogram leaving it on the list and a use-after-free can trigger. Update the clock argument first and if it fails then exit gracefully before the histogram trigger is placed on any lists. - Restore :mod: trailer after parsing in ftrace_set_clr_event The function ftrace_set_clr_event() modifies the parse string and needs to put it back to what was passed in. It searches for ":mod:" via a strsep() but fails to put back the first ':' in the string. Add back the ':' in the passed in string. - Take trace_array reference when opening a tracer options file The options files are dynamically created and some tracers add their own options. When a tracer adds their own list of options, the trace_array holding them has an array to hold the list of options for each tracer. This array increases in size via a krealloc(), and the new entry gets a newly allocated array to hold the options of the new tracer being added. The element in each entry of the tracer's option array holds a pointer back to the trace_array, a pointer to the tracer it is associated to, a pointer to the flags of the option. The issue is that these arrays are freed when the trace_array is freed when its instance it represents is removed from the instances directory. There's a race that an open of one of these options files can happen when the instance is being removed. Add a new helper function to be called by the open function of the options file to iterate all existing trace_arrays under a lock and find the one that has the given option element in one of it's tracer arrays. If found, then update the associated trace_array's reference counter to keep it from being freed. If not found, have the open call return -ENODEV. - Disable interrupts when acquiring the lock in rb_wake_up_waiters() The function rb_wake_up_waiters() assumes it will be called in interrupt context and does not disable irqs when taking cpu_buffer->reader_lock, which can be called in hard interrupt context. The issue is in PREEMPT_RT, this function is called in thread context leaving this lock open to a deadlock. Take the lock with interrupts disabled. - Use rcu_assign_pointer() for tmp_ops filter hash The tmp_ops used in update_ftrace_direct_mod() assigns its filter_hash field directly, but that field is annotated as __rcu and sparse complains. Assign it with rcu_assign_pointer() - Fix use-after-free in enable_trigger_private_data_free() The trace_event_call is accessed through the event_trigger_data's trace_event_file pointer to put the trace_event_call on freeing. The issue is that the trace_event_file data may have been freed already causing a use-after-free. Add a field to the event_trigger_data that points directly to the trace_event_call so that it can decrement its reference directly without needing to go through the trace_event_file. - Fix accounting of buffer data remote headers trace_buffer_desc_size() and trace_remote_alloc_buffer() undercount the number of pages is needed for the asked for size as it doesn't take into account the meta data on each page. Add a helper function to do the calculation properly and use that in these functions. - Catch nr_page_va overflow in ring_buffer_desc sizing The number of pages per remote ring buffer is capped by ring_buffer_desc::nr_page_va (32 bits). A buffer_size large enough to overflow that field would silently allocate a descriptor smaller than what was asked for. - Do not resize the subbuf order if any per_cpu buffer is disabled The mmapping of ring buffers disables resizing the subbuffers, but it is done per-cpu whereas the subbuf size change is done for all the per_cpu buffers under the buffer->mutex. It could change the size of some while the mapping is happening on others. Have the resize of the subbuf order check all the per_cpu buffers under the lock to see if any of them is disabled before starting and causing an inconsistency between buffers that are being mapped. * tag 'trace-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (25 commits) ring-buffer: Check resize_disabled before publishing the new subbuf order tracing/remotes: Catch nr_page_va overflow in ring_buffer_desc sizing tracing/remotes: Account for ring buffer page header in size calculation tracing: Don't dereference trace_event_file in deferred trigger free ftrace: Use rcu_assign_pointer() for tmp_ops filter hash ring-buffer: Acquire the lock with irqsave in rb_wake_up_waiters() tracing: Take trace_array reference when opening a tracer options file tracing: Fix ring_buffer_read_page_size() kernel-doc tracing: Restore :mod: trailer after parsing in ftrace_set_clr_event() tracing: Fix memory corruption from a "STACKTRACE" histogram key tracing: Fix memory corruption from the histogram stacktrace modifier tracing: Undo the registration when enabling the histogram trigger fails tracing: Take the reference before publishing the named histogram trigger tracing: Set the trace clock before registering the histogram trigger tracing: Fix typo "preceeded" in comment tracing: Fix typo "availabe" in comment tracing: Let histogram values keep the percent and graph modifiers tracing: Keep the entry count when the histogram stats allocation fails tracing: Free histogram the field rejected for a bad modifier tracing: Free histogram the var ref when its initialization fails ... --- drivers/video/fbdev/68328fb.c | 482 + drivers/video/fbdev/Kconfig | 1805 +++ drivers/video/fbdev/Makefile | 126 + drivers/video/fbdev/acornfb.c | 1102 ++ drivers/video/fbdev/acornfb.h | 166 + drivers/video/fbdev/amifb.c | 3787 ++++++ drivers/video/fbdev/arcfb.c | 616 + drivers/video/fbdev/arkfb.c | 1218 ++ drivers/video/fbdev/asiliantfb.c | 632 + drivers/video/fbdev/atafb.c | 3474 ++++++ drivers/video/fbdev/atafb.h | 37 + drivers/video/fbdev/atafb_iplan2p2.c | 270 + drivers/video/fbdev/atafb_iplan2p4.c | 285 + drivers/video/fbdev/atafb_iplan2p8.c | 322 + drivers/video/fbdev/atafb_mfb.c | 89 + drivers/video/fbdev/atafb_utils.h | 401 + drivers/video/fbdev/atmel_lcdfb.c | 1312 +++ drivers/video/fbdev/aty/Makefile | 16 + drivers/video/fbdev/aty/ati_ids.h | 215 + drivers/video/fbdev/aty/aty128fb.c | 2467 ++++ drivers/video/fbdev/aty/atyfb.h | 371 + drivers/video/fbdev/aty/atyfb_base.c | 4012 +++++++ drivers/video/fbdev/aty/mach64_accel.c | 429 + drivers/video/fbdev/aty/mach64_ct.c | 651 ++ drivers/video/fbdev/aty/mach64_cursor.c | 231 + drivers/video/fbdev/aty/mach64_gx.c | 908 ++ drivers/video/fbdev/aty/radeon_accel.c | 329 + drivers/video/fbdev/aty/radeon_backlight.c | 208 + drivers/video/fbdev/aty/radeon_base.c | 2655 +++++ drivers/video/fbdev/aty/radeon_i2c.c | 168 + drivers/video/fbdev/aty/radeon_monitor.c | 1051 ++ drivers/video/fbdev/aty/radeon_pm.c | 2927 +++++ drivers/video/fbdev/aty/radeonfb.h | 520 + drivers/video/fbdev/au1100fb.c | 928 ++ drivers/video/fbdev/au1200fb.c | 1843 +++ drivers/video/fbdev/au1200fb.h | 286 + drivers/video/fbdev/broadsheetfb.c | 1169 ++ drivers/video/fbdev/bt431.h | 240 + drivers/video/fbdev/bt455.h | 90 + drivers/video/fbdev/bw2.c | 397 + drivers/video/fbdev/c2p.h | 19 + drivers/video/fbdev/c2p_core.h | 153 + drivers/video/fbdev/c2p_iplan2.c | 154 + drivers/video/fbdev/c2p_planar.c | 158 + drivers/video/fbdev/carminefb.c | 793 ++ drivers/video/fbdev/carminefb.h | 65 + drivers/video/fbdev/carminefb_regs.h | 160 + drivers/video/fbdev/cg14.c | 615 + drivers/video/fbdev/cg3.c | 483 + drivers/video/fbdev/cg6.c | 883 ++ drivers/video/fbdev/chipsfb.c | 530 + drivers/video/fbdev/cirrusfb.c | 2954 +++++ drivers/video/fbdev/clps711x-fb.c | 372 + drivers/video/fbdev/cobalt_lcdfb.c | 350 + drivers/video/fbdev/controlfb.c | 1018 ++ drivers/video/fbdev/controlfb.h | 143 + drivers/video/fbdev/core/Kconfig | 207 + drivers/video/fbdev/core/Makefile | 37 + drivers/video/fbdev/core/bitblit.c | 399 + drivers/video/fbdev/core/cfbcopyarea.c | 36 + drivers/video/fbdev/core/cfbfillrect.c | 36 + drivers/video/fbdev/core/cfbimgblt.c | 36 + drivers/video/fbdev/core/cfbmem.h | 43 + drivers/video/fbdev/core/fb_backlight.c | 51 + drivers/video/fbdev/core/fb_chrdev.c | 438 + drivers/video/fbdev/core/fb_cmdline.c | 61 + drivers/video/fbdev/core/fb_copyarea.h | 405 + drivers/video/fbdev/core/fb_ddc.c | 127 + drivers/video/fbdev/core/fb_defio.c | 479 + drivers/video/fbdev/core/fb_draw.h | 163 + drivers/video/fbdev/core/fb_fillrect.h | 279 + drivers/video/fbdev/core/fb_imageblit.h | 495 + drivers/video/fbdev/core/fb_info.c | 80 + drivers/video/fbdev/core/fb_internal.h | 85 + drivers/video/fbdev/core/fb_io_fops.c | 197 + drivers/video/fbdev/core/fb_logo.c | 508 + drivers/video/fbdev/core/fb_notify.c | 54 + drivers/video/fbdev/core/fb_procfs.c | 62 + drivers/video/fbdev/core/fb_sys_fops.c | 132 + drivers/video/fbdev/core/fbcmap.c | 363 + drivers/video/fbdev/core/fbcon.c | 3416 ++++++ drivers/video/fbdev/core/fbcon.h | 286 + drivers/video/fbdev/core/fbcon_ccw.c | 376 + drivers/video/fbdev/core/fbcon_cw.c | 359 + drivers/video/fbdev/core/fbcon_rotate.c | 52 + drivers/video/fbdev/core/fbcon_rotate.h | 37 + drivers/video/fbdev/core/fbcon_ud.c | 410 + drivers/video/fbdev/core/fbcvt.c | 368 + drivers/video/fbdev/core/fbmem.c | 802 ++ drivers/video/fbdev/core/fbmon.c | 1525 +++ drivers/video/fbdev/core/fbsysfs.c | 519 + drivers/video/fbdev/core/modedb.c | 1208 ++ drivers/video/fbdev/core/softcursor.c | 76 + drivers/video/fbdev/core/svgalib.c | 664 ++ drivers/video/fbdev/core/syscopyarea.c | 30 + drivers/video/fbdev/core/sysfillrect.c | 30 + drivers/video/fbdev/core/sysimgblt.c | 30 + drivers/video/fbdev/core/sysmem.h | 39 + drivers/video/fbdev/core/tileblit.c | 188 + drivers/video/fbdev/cyber2000fb.c | 1871 +++ drivers/video/fbdev/cyber2000fb.h | 492 + drivers/video/fbdev/dnfb.c | 307 + drivers/video/fbdev/edid.h | 138 + drivers/video/fbdev/efifb.c | 608 + drivers/video/fbdev/ep93xx-fb.c | 606 + drivers/video/fbdev/ffb.c | 1090 ++ drivers/video/fbdev/fm2fb.c | 320 + drivers/video/fbdev/fsl-diu-fb.c | 1995 ++++ drivers/video/fbdev/g364fb.c | 230 + drivers/video/fbdev/gbefb.c | 1287 +++ drivers/video/fbdev/geode/Kconfig | 50 + drivers/video/fbdev/geode/Makefile | 10 + drivers/video/fbdev/geode/display_gx.c | 181 + drivers/video/fbdev/geode/display_gx1.c | 210 + drivers/video/fbdev/geode/display_gx1.h | 150 + drivers/video/fbdev/geode/geodefb.h | 34 + drivers/video/fbdev/geode/gx1fb_core.c | 478 + drivers/video/fbdev/geode/gxfb.h | 349 + drivers/video/fbdev/geode/gxfb_core.c | 543 + drivers/video/fbdev/geode/lxfb.h | 443 + drivers/video/fbdev/geode/lxfb_core.c | 680 ++ drivers/video/fbdev/geode/lxfb_ops.c | 839 ++ drivers/video/fbdev/geode/suspend_gx.c | 259 + drivers/video/fbdev/geode/video_cs5530.c | 189 + drivers/video/fbdev/geode/video_cs5530.h | 71 + drivers/video/fbdev/geode/video_gx.c | 345 + drivers/video/fbdev/goldfishfb.c | 322 + drivers/video/fbdev/grvga.c | 550 + drivers/video/fbdev/gxt4500.c | 801 ++ drivers/video/fbdev/hecubafb.c | 251 + drivers/video/fbdev/hitfb.c | 514 + drivers/video/fbdev/hpfb.c | 428 + drivers/video/fbdev/i740_reg.h | 309 + drivers/video/fbdev/i740fb.c | 1316 +++ drivers/video/fbdev/i810/Makefile | 18 + drivers/video/fbdev/i810/i810-i2c.c | 175 + drivers/video/fbdev/i810/i810.h | 298 + drivers/video/fbdev/i810/i810_accel.c | 456 + drivers/video/fbdev/i810/i810_dvt.c | 313 + drivers/video/fbdev/i810/i810_gtf.c | 276 + drivers/video/fbdev/i810/i810_main.c | 2234 ++++ drivers/video/fbdev/i810/i810_main.h | 69 + drivers/video/fbdev/i810/i810_regs.h | 275 + drivers/video/fbdev/imsttfb.c | 1650 +++ drivers/video/fbdev/imxfb.c | 1106 ++ drivers/video/fbdev/kyro/Makefile | 9 + drivers/video/fbdev/kyro/STG4000InitDevice.c | 323 + drivers/video/fbdev/kyro/STG4000Interface.h | 61 + drivers/video/fbdev/kyro/STG4000OverlayDevice.c | 600 + drivers/video/fbdev/kyro/STG4000Ramdac.c | 163 + drivers/video/fbdev/kyro/STG4000Reg.h | 283 + drivers/video/fbdev/kyro/STG4000VTG.c | 170 + drivers/video/fbdev/kyro/fbdev.c | 836 ++ drivers/video/fbdev/leo.c | 682 ++ drivers/video/fbdev/macfb.c | 899 ++ drivers/video/fbdev/macmodes.c | 416 + drivers/video/fbdev/macmodes.h | 71 + drivers/video/fbdev/matrox/Makefile | 12 + drivers/video/fbdev/matrox/g450_pll.c | 519 + drivers/video/fbdev/matrox/g450_pll.h | 13 + drivers/video/fbdev/matrox/i2c-matroxfb.c | 234 + drivers/video/fbdev/matrox/matroxfb_DAC1064.c | 1116 ++ drivers/video/fbdev/matrox/matroxfb_DAC1064.h | 180 + drivers/video/fbdev/matrox/matroxfb_Ti3026.c | 751 ++ drivers/video/fbdev/matrox/matroxfb_Ti3026.h | 12 + drivers/video/fbdev/matrox/matroxfb_accel.c | 523 + drivers/video/fbdev/matrox/matroxfb_accel.h | 9 + drivers/video/fbdev/matrox/matroxfb_base.c | 2598 +++++ drivers/video/fbdev/matrox/matroxfb_base.h | 709 ++ drivers/video/fbdev/matrox/matroxfb_crtc2.c | 736 ++ drivers/video/fbdev/matrox/matroxfb_crtc2.h | 35 + drivers/video/fbdev/matrox/matroxfb_g450.c | 643 ++ drivers/video/fbdev/matrox/matroxfb_g450.h | 15 + drivers/video/fbdev/matrox/matroxfb_maven.c | 1302 +++ drivers/video/fbdev/matrox/matroxfb_maven.h | 21 + drivers/video/fbdev/matrox/matroxfb_misc.c | 820 ++ drivers/video/fbdev/matrox/matroxfb_misc.h | 22 + drivers/video/fbdev/maxinefb.c | 175 + drivers/video/fbdev/mb862xx/Makefile | 9 + drivers/video/fbdev/mb862xx/mb862xx-i2c.c | 167 + drivers/video/fbdev/mb862xx/mb862xx_reg.h | 189 + drivers/video/fbdev/mb862xx/mb862xxfb.h | 122 + drivers/video/fbdev/mb862xx/mb862xxfb_accel.c | 326 + drivers/video/fbdev/mb862xx/mb862xxfb_accel.h | 204 + drivers/video/fbdev/mb862xx/mb862xxfbdrv.c | 1207 ++ drivers/video/fbdev/metronomefb.c | 728 ++ drivers/video/fbdev/mmp/Kconfig | 12 + drivers/video/fbdev/mmp/Makefile | 4 + drivers/video/fbdev/mmp/core.c | 239 + drivers/video/fbdev/mmp/fb/Kconfig | 8 + drivers/video/fbdev/mmp/fb/Makefile | 2 + drivers/video/fbdev/mmp/fb/mmpfb.c | 661 ++ drivers/video/fbdev/mmp/fb/mmpfb.h | 41 + drivers/video/fbdev/mmp/hw/Kconfig | 17 + drivers/video/fbdev/mmp/hw/Makefile | 3 + drivers/video/fbdev/mmp/hw/mmp_ctrl.c | 575 + drivers/video/fbdev/mmp/hw/mmp_ctrl.h | 1456 +++ drivers/video/fbdev/mmp/hw/mmp_spi.c | 167 + drivers/video/fbdev/mmp/panel/Kconfig | 6 + drivers/video/fbdev/mmp/panel/Makefile | 2 + drivers/video/fbdev/mmp/panel/tpo_tj032md01bw.c | 172 + drivers/video/fbdev/n411.c | 208 + drivers/video/fbdev/neofb.c | 2218 ++++ drivers/video/fbdev/nvidia/Makefile | 13 + drivers/video/fbdev/nvidia/nv_accel.c | 418 + drivers/video/fbdev/nvidia/nv_backlight.c | 131 + drivers/video/fbdev/nvidia/nv_dma.h | 188 + drivers/video/fbdev/nvidia/nv_hw.c | 1688 +++ drivers/video/fbdev/nvidia/nv_i2c.c | 171 + drivers/video/fbdev/nvidia/nv_local.h | 114 + drivers/video/fbdev/nvidia/nv_of.c | 78 + drivers/video/fbdev/nvidia/nv_proto.h | 68 + drivers/video/fbdev/nvidia/nv_setup.c | 649 ++ drivers/video/fbdev/nvidia/nv_type.h | 176 + drivers/video/fbdev/nvidia/nvidia.c | 1596 +++ drivers/video/fbdev/ocfb.c | 428 + drivers/video/fbdev/offb.c | 726 ++ drivers/video/fbdev/omap/Kconfig | 49 + drivers/video/fbdev/omap/Makefile | 26 + drivers/video/fbdev/omap/hwa742.c | 1061 ++ drivers/video/fbdev/omap/lcd_ams_delta.c | 175 + drivers/video/fbdev/omap/lcd_dma.c | 445 + drivers/video/fbdev/omap/lcd_dma.h | 63 + drivers/video/fbdev/omap/lcd_mipid.c | 606 + drivers/video/fbdev/omap/lcd_palmte.c | 52 + drivers/video/fbdev/omap/lcdc.c | 782 ++ drivers/video/fbdev/omap/lcdc.h | 45 + drivers/video/fbdev/omap/omapfb.h | 230 + drivers/video/fbdev/omap/omapfb_main.c | 1925 ++++ drivers/video/fbdev/omap/sossi.c | 683 ++ drivers/video/fbdev/omap2/Kconfig | 6 + drivers/video/fbdev/omap2/Makefile | 2 + drivers/video/fbdev/omap2/omapfb/Kconfig | 40 + drivers/video/fbdev/omap2/omapfb/Makefile | 6 + drivers/video/fbdev/omap2/omapfb/displays/Kconfig | 93 + drivers/video/fbdev/omap2/omapfb/displays/Makefile | 15 + .../omap2/omapfb/displays/connector-analog-tv.c | 259 + .../fbdev/omap2/omapfb/displays/connector-dvi.c | 342 + .../fbdev/omap2/omapfb/displays/connector-hdmi.c | 286 + .../fbdev/omap2/omapfb/displays/encoder-opa362.c | 271 + .../fbdev/omap2/omapfb/displays/encoder-tfp410.c | 258 + .../omap2/omapfb/displays/encoder-tpd12s015.c | 324 + .../video/fbdev/omap2/omapfb/displays/panel-dpi.c | 248 + .../fbdev/omap2/omapfb/displays/panel-dsi-cm.c | 1286 +++ .../omapfb/displays/panel-lgphilips-lb035q02.c | 335 + .../omap2/omapfb/displays/panel-nec-nl8048hl11.c | 361 + .../omapfb/displays/panel-sharp-ls037v7dw01.c | 329 + .../omap2/omapfb/displays/panel-sony-acx565akm.c | 858 ++ .../omap2/omapfb/displays/panel-tpo-td028ttec1.c | 476 + .../omap2/omapfb/displays/panel-tpo-td043mtea1.c | 611 + drivers/video/fbdev/omap2/omapfb/dss/Kconfig | 111 + drivers/video/fbdev/omap2/omapfb/dss/Makefile | 18 + drivers/video/fbdev/omap2/omapfb/dss/apply.c | 1690 +++ drivers/video/fbdev/omap2/omapfb/dss/core.c | 287 + .../video/fbdev/omap2/omapfb/dss/dispc-compat.c | 658 ++ .../video/fbdev/omap2/omapfb/dss/dispc-compat.h | 19 + drivers/video/fbdev/omap2/omapfb/dss/dispc.c | 4059 +++++++ drivers/video/fbdev/omap2/omapfb/dss/dispc.h | 907 ++ drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c | 314 + .../video/fbdev/omap2/omapfb/dss/display-sysfs.c | 347 + drivers/video/fbdev/omap2/omapfb/dss/display.c | 328 + drivers/video/fbdev/omap2/omapfb/dss/dpi.c | 887 ++ drivers/video/fbdev/omap2/omapfb/dss/dsi.c | 5578 +++++++++ drivers/video/fbdev/omap2/omapfb/dss/dss-of.c | 78 + drivers/video/fbdev/omap2/omapfb/dss/dss.c | 1296 +++ drivers/video/fbdev/omap2/omapfb/dss/dss.h | 519 + .../video/fbdev/omap2/omapfb/dss/dss_features.c | 940 ++ .../video/fbdev/omap2/omapfb/dss/dss_features.h | 97 + drivers/video/fbdev/omap2/omapfb/dss/hdmi.h | 360 + drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c | 812 ++ drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c | 885 ++ drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h | 262 + drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c | 854 ++ drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c | 878 ++ drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h | 292 + drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c | 149 + drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c | 221 + drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c | 235 + drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c | 281 + .../video/fbdev/omap2/omapfb/dss/manager-sysfs.c | 516 + drivers/video/fbdev/omap2/omapfb/dss/manager.c | 251 + .../fbdev/omap2/omapfb/dss/omapdss-boot-init.c | 216 + drivers/video/fbdev/omap2/omapfb/dss/output.c | 257 + .../video/fbdev/omap2/omapfb/dss/overlay-sysfs.c | 447 + drivers/video/fbdev/omap2/omapfb/dss/overlay.c | 191 + drivers/video/fbdev/omap2/omapfb/dss/pll.c | 378 + drivers/video/fbdev/omap2/omapfb/dss/sdi.c | 442 + drivers/video/fbdev/omap2/omapfb/dss/venc.c | 941 ++ drivers/video/fbdev/omap2/omapfb/dss/video-pll.c | 189 + drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c | 915 ++ drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2641 +++++ drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c | 598 + drivers/video/fbdev/omap2/omapfb/omapfb.h | 196 + drivers/video/fbdev/omap2/omapfb/vrfb.c | 379 + drivers/video/fbdev/p9100.c | 372 + drivers/video/fbdev/platinumfb.c | 722 ++ drivers/video/fbdev/platinumfb.h | 368 + drivers/video/fbdev/pm2fb.c | 1855 +++ drivers/video/fbdev/pm3fb.c | 1578 +++ drivers/video/fbdev/pmag-aa-fb.c | 301 + drivers/video/fbdev/pmag-ba-fb.c | 290 + drivers/video/fbdev/pmagb-b-fb.c | 408 + drivers/video/fbdev/ps3fb.c | 1301 +++ drivers/video/fbdev/pvr2fb.c | 1149 ++ drivers/video/fbdev/pxa168fb.c | 808 ++ drivers/video/fbdev/pxa168fb.h | 559 + drivers/video/fbdev/pxa3xx-gcu.c | 712 ++ drivers/video/fbdev/pxa3xx-gcu.h | 39 + drivers/video/fbdev/pxa3xx-regs.h | 180 + drivers/video/fbdev/pxafb.c | 2439 ++++ drivers/video/fbdev/pxafb.h | 204 + drivers/video/fbdev/q40fb.c | 151 + drivers/video/fbdev/riva/Makefile | 12 + drivers/video/fbdev/riva/fbdev.c | 2157 ++++ drivers/video/fbdev/riva/nv_driver.c | 423 + drivers/video/fbdev/riva/nv_type.h | 59 + drivers/video/fbdev/riva/nvreg.h | 188 + drivers/video/fbdev/riva/riva_hw.c | 2237 ++++ drivers/video/fbdev/riva/riva_hw.h | 564 + drivers/video/fbdev/riva/riva_tbl.h | 1008 ++ drivers/video/fbdev/riva/rivafb-i2c.c | 166 + drivers/video/fbdev/riva/rivafb.h | 76 + drivers/video/fbdev/s1d13xxxfb.c | 1040 ++ drivers/video/fbdev/s3c-fb.c | 1802 +++ drivers/video/fbdev/s3fb.c | 1659 +++ drivers/video/fbdev/sa1100fb.c | 1226 ++ drivers/video/fbdev/sa1100fb.h | 101 + drivers/video/fbdev/savage/Makefile | 10 + drivers/video/fbdev/savage/savagefb-i2c.c | 241 + drivers/video/fbdev/savage/savagefb.h | 406 + drivers/video/fbdev/savage/savagefb_accel.c | 137 + drivers/video/fbdev/savage/savagefb_driver.c | 2579 +++++ drivers/video/fbdev/sbuslib.c | 288 + drivers/video/fbdev/sbuslib.h | 63 + drivers/video/fbdev/sh7760fb.c | 584 + drivers/video/fbdev/sh_mobile_lcdcfb.c | 2651 +++++ drivers/video/fbdev/sh_mobile_lcdcfb.h | 107 + drivers/video/fbdev/simplefb.c | 693 ++ drivers/video/fbdev/sis/300vtbl.h | 1070 ++ drivers/video/fbdev/sis/310vtbl.h | 1339 +++ drivers/video/fbdev/sis/Makefile | 8 + drivers/video/fbdev/sis/init.c | 3631 ++++++ drivers/video/fbdev/sis/init.h | 1465 +++ drivers/video/fbdev/sis/init301.c | 11379 +++++++++++++++++++ drivers/video/fbdev/sis/init301.h | 136 + drivers/video/fbdev/sis/initdef.h | 708 ++ drivers/video/fbdev/sis/initextlfb.c | 218 + drivers/video/fbdev/sis/oem300.h | 840 ++ drivers/video/fbdev/sis/oem310.h | 432 + drivers/video/fbdev/sis/sis.h | 701 ++ drivers/video/fbdev/sis/sis_accel.c | 410 + drivers/video/fbdev/sis/sis_accel.h | 387 + drivers/video/fbdev/sis/sis_main.c | 6817 +++++++++++ drivers/video/fbdev/sis/sis_main.h | 651 ++ drivers/video/fbdev/sis/vgatypes.h | 97 + drivers/video/fbdev/sis/vstruct.h | 551 + drivers/video/fbdev/skeletonfb.c | 1032 ++ drivers/video/fbdev/sm501fb.c | 2248 ++++ drivers/video/fbdev/sm712.h | 112 + drivers/video/fbdev/sm712fb.c | 1779 +++ drivers/video/fbdev/smscufx.c | 1953 ++++ drivers/video/fbdev/ssd1307fb.c | 875 ++ drivers/video/fbdev/sstfb.c | 1544 +++ drivers/video/fbdev/stifb.c | 1531 +++ drivers/video/fbdev/sunxvr1000.c | 197 + drivers/video/fbdev/sunxvr2500.c | 250 + drivers/video/fbdev/sunxvr500.c | 442 + drivers/video/fbdev/tcx.c | 530 + drivers/video/fbdev/tdfxfb.c | 1827 +++ drivers/video/fbdev/tgafb.c | 1629 +++ drivers/video/fbdev/tridentfb.c | 1841 +++ drivers/video/fbdev/udlfb.c | 2000 ++++ drivers/video/fbdev/uvesafb.c | 1999 ++++ drivers/video/fbdev/valkyriefb.c | 577 + drivers/video/fbdev/valkyriefb.h | 196 + drivers/video/fbdev/vesafb.c | 526 + drivers/video/fbdev/vfb.c | 556 + drivers/video/fbdev/vga16fb.c | 1442 +++ drivers/video/fbdev/via/Makefile | 13 + drivers/video/fbdev/via/accel.c | 533 + drivers/video/fbdev/via/accel.h | 197 + drivers/video/fbdev/via/chip.h | 162 + drivers/video/fbdev/via/debug.h | 29 + drivers/video/fbdev/via/dvi.c | 464 + drivers/video/fbdev/via/dvi.h | 51 + drivers/video/fbdev/via/global.c | 36 + drivers/video/fbdev/via/global.h | 72 + drivers/video/fbdev/via/hw.c | 2119 ++++ drivers/video/fbdev/via/hw.h | 662 ++ drivers/video/fbdev/via/ioctl.c | 102 + drivers/video/fbdev/via/ioctl.h | 189 + drivers/video/fbdev/via/lcd.c | 993 ++ drivers/video/fbdev/via/lcd.h | 75 + drivers/video/fbdev/via/share.h | 318 + drivers/video/fbdev/via/tblDPASetting.c | 72 + drivers/video/fbdev/via/tblDPASetting.h | 31 + drivers/video/fbdev/via/via-core.c | 759 ++ drivers/video/fbdev/via/via-gpio.c | 305 + drivers/video/fbdev/via/via-gpio.h | 13 + drivers/video/fbdev/via/via_aux.c | 73 + drivers/video/fbdev/via/via_aux.h | 78 + drivers/video/fbdev/via/via_aux_ch7301.c | 35 + drivers/video/fbdev/via/via_aux_edid.c | 85 + drivers/video/fbdev/via/via_aux_sii164.c | 39 + drivers/video/fbdev/via/via_aux_vt1621.c | 29 + drivers/video/fbdev/via/via_aux_vt1622.c | 35 + drivers/video/fbdev/via/via_aux_vt1625.c | 35 + drivers/video/fbdev/via/via_aux_vt1631.c | 31 + drivers/video/fbdev/via/via_aux_vt1632.c | 39 + drivers/video/fbdev/via/via_aux_vt1636.c | 31 + drivers/video/fbdev/via/via_clock.c | 353 + drivers/video/fbdev/via/via_clock.h | 61 + drivers/video/fbdev/via/via_i2c.c | 280 + drivers/video/fbdev/via/via_modesetting.c | 215 + drivers/video/fbdev/via/via_modesetting.h | 46 + drivers/video/fbdev/via/via_utility.c | 228 + drivers/video/fbdev/via/via_utility.h | 20 + drivers/video/fbdev/via/viafbdev.c | 2148 ++++ drivers/video/fbdev/via/viafbdev.h | 96 + drivers/video/fbdev/via/viamode.c | 369 + drivers/video/fbdev/via/viamode.h | 49 + drivers/video/fbdev/via/vt1636.c | 230 + drivers/video/fbdev/via/vt1636.h | 30 + drivers/video/fbdev/vt8500lcdfb.c | 489 + drivers/video/fbdev/vt8500lcdfb.h | 26 + drivers/video/fbdev/vt8623fb.c | 954 ++ drivers/video/fbdev/wm8505fb.c | 407 + drivers/video/fbdev/wm8505fb_regs.h | 68 + drivers/video/fbdev/wmt_ge_rops.c | 191 + drivers/video/fbdev/wmt_ge_rops.h | 29 + drivers/video/fbdev/xen-fbfront.c | 699 ++ drivers/video/fbdev/xilinxfb.c | 502 + 432 files changed, 267055 insertions(+) create mode 100644 drivers/video/fbdev/68328fb.c create mode 100644 drivers/video/fbdev/Kconfig create mode 100644 drivers/video/fbdev/Makefile create mode 100644 drivers/video/fbdev/acornfb.c create mode 100644 drivers/video/fbdev/acornfb.h create mode 100644 drivers/video/fbdev/amifb.c create mode 100644 drivers/video/fbdev/arcfb.c create mode 100644 drivers/video/fbdev/arkfb.c create mode 100644 drivers/video/fbdev/asiliantfb.c create mode 100644 drivers/video/fbdev/atafb.c create mode 100644 drivers/video/fbdev/atafb.h create mode 100644 drivers/video/fbdev/atafb_iplan2p2.c create mode 100644 drivers/video/fbdev/atafb_iplan2p4.c create mode 100644 drivers/video/fbdev/atafb_iplan2p8.c create mode 100644 drivers/video/fbdev/atafb_mfb.c create mode 100644 drivers/video/fbdev/atafb_utils.h create mode 100644 drivers/video/fbdev/atmel_lcdfb.c create mode 100644 drivers/video/fbdev/aty/Makefile create mode 100644 drivers/video/fbdev/aty/ati_ids.h create mode 100644 drivers/video/fbdev/aty/aty128fb.c create mode 100644 drivers/video/fbdev/aty/atyfb.h create mode 100644 drivers/video/fbdev/aty/atyfb_base.c create mode 100644 drivers/video/fbdev/aty/mach64_accel.c create mode 100644 drivers/video/fbdev/aty/mach64_ct.c create mode 100644 drivers/video/fbdev/aty/mach64_cursor.c create mode 100644 drivers/video/fbdev/aty/mach64_gx.c create mode 100644 drivers/video/fbdev/aty/radeon_accel.c create mode 100644 drivers/video/fbdev/aty/radeon_backlight.c create mode 100644 drivers/video/fbdev/aty/radeon_base.c create mode 100644 drivers/video/fbdev/aty/radeon_i2c.c create mode 100644 drivers/video/fbdev/aty/radeon_monitor.c create mode 100644 drivers/video/fbdev/aty/radeon_pm.c create mode 100644 drivers/video/fbdev/aty/radeonfb.h create mode 100644 drivers/video/fbdev/au1100fb.c create mode 100644 drivers/video/fbdev/au1200fb.c create mode 100644 drivers/video/fbdev/au1200fb.h create mode 100644 drivers/video/fbdev/broadsheetfb.c create mode 100644 drivers/video/fbdev/bt431.h create mode 100644 drivers/video/fbdev/bt455.h create mode 100644 drivers/video/fbdev/bw2.c create mode 100644 drivers/video/fbdev/c2p.h create mode 100644 drivers/video/fbdev/c2p_core.h create mode 100644 drivers/video/fbdev/c2p_iplan2.c create mode 100644 drivers/video/fbdev/c2p_planar.c create mode 100644 drivers/video/fbdev/carminefb.c create mode 100644 drivers/video/fbdev/carminefb.h create mode 100644 drivers/video/fbdev/carminefb_regs.h create mode 100644 drivers/video/fbdev/cg14.c create mode 100644 drivers/video/fbdev/cg3.c create mode 100644 drivers/video/fbdev/cg6.c create mode 100644 drivers/video/fbdev/chipsfb.c create mode 100644 drivers/video/fbdev/cirrusfb.c create mode 100644 drivers/video/fbdev/clps711x-fb.c create mode 100644 drivers/video/fbdev/cobalt_lcdfb.c create mode 100644 drivers/video/fbdev/controlfb.c create mode 100644 drivers/video/fbdev/controlfb.h create mode 100644 drivers/video/fbdev/core/Kconfig create mode 100644 drivers/video/fbdev/core/Makefile create mode 100644 drivers/video/fbdev/core/bitblit.c create mode 100644 drivers/video/fbdev/core/cfbcopyarea.c create mode 100644 drivers/video/fbdev/core/cfbfillrect.c create mode 100644 drivers/video/fbdev/core/cfbimgblt.c create mode 100644 drivers/video/fbdev/core/cfbmem.h create mode 100644 drivers/video/fbdev/core/fb_backlight.c create mode 100644 drivers/video/fbdev/core/fb_chrdev.c create mode 100644 drivers/video/fbdev/core/fb_cmdline.c create mode 100644 drivers/video/fbdev/core/fb_copyarea.h create mode 100644 drivers/video/fbdev/core/fb_ddc.c create mode 100644 drivers/video/fbdev/core/fb_defio.c create mode 100644 drivers/video/fbdev/core/fb_draw.h create mode 100644 drivers/video/fbdev/core/fb_fillrect.h create mode 100644 drivers/video/fbdev/core/fb_imageblit.h create mode 100644 drivers/video/fbdev/core/fb_info.c create mode 100644 drivers/video/fbdev/core/fb_internal.h create mode 100644 drivers/video/fbdev/core/fb_io_fops.c create mode 100644 drivers/video/fbdev/core/fb_logo.c create mode 100644 drivers/video/fbdev/core/fb_notify.c create mode 100644 drivers/video/fbdev/core/fb_procfs.c create mode 100644 drivers/video/fbdev/core/fb_sys_fops.c create mode 100644 drivers/video/fbdev/core/fbcmap.c create mode 100644 drivers/video/fbdev/core/fbcon.c create mode 100644 drivers/video/fbdev/core/fbcon.h create mode 100644 drivers/video/fbdev/core/fbcon_ccw.c create mode 100644 drivers/video/fbdev/core/fbcon_cw.c create mode 100644 drivers/video/fbdev/core/fbcon_rotate.c create mode 100644 drivers/video/fbdev/core/fbcon_rotate.h create mode 100644 drivers/video/fbdev/core/fbcon_ud.c create mode 100644 drivers/video/fbdev/core/fbcvt.c create mode 100644 drivers/video/fbdev/core/fbmem.c create mode 100644 drivers/video/fbdev/core/fbmon.c create mode 100644 drivers/video/fbdev/core/fbsysfs.c create mode 100644 drivers/video/fbdev/core/modedb.c create mode 100644 drivers/video/fbdev/core/softcursor.c create mode 100644 drivers/video/fbdev/core/svgalib.c create mode 100644 drivers/video/fbdev/core/syscopyarea.c create mode 100644 drivers/video/fbdev/core/sysfillrect.c create mode 100644 drivers/video/fbdev/core/sysimgblt.c create mode 100644 drivers/video/fbdev/core/sysmem.h create mode 100644 drivers/video/fbdev/core/tileblit.c create mode 100644 drivers/video/fbdev/cyber2000fb.c create mode 100644 drivers/video/fbdev/cyber2000fb.h create mode 100644 drivers/video/fbdev/dnfb.c create mode 100644 drivers/video/fbdev/edid.h create mode 100644 drivers/video/fbdev/efifb.c create mode 100644 drivers/video/fbdev/ep93xx-fb.c create mode 100644 drivers/video/fbdev/ffb.c create mode 100644 drivers/video/fbdev/fm2fb.c create mode 100644 drivers/video/fbdev/fsl-diu-fb.c create mode 100644 drivers/video/fbdev/g364fb.c create mode 100644 drivers/video/fbdev/gbefb.c create mode 100644 drivers/video/fbdev/geode/Kconfig create mode 100644 drivers/video/fbdev/geode/Makefile create mode 100644 drivers/video/fbdev/geode/display_gx.c create mode 100644 drivers/video/fbdev/geode/display_gx1.c create mode 100644 drivers/video/fbdev/geode/display_gx1.h create mode 100644 drivers/video/fbdev/geode/geodefb.h create mode 100644 drivers/video/fbdev/geode/gx1fb_core.c create mode 100644 drivers/video/fbdev/geode/gxfb.h create mode 100644 drivers/video/fbdev/geode/gxfb_core.c create mode 100644 drivers/video/fbdev/geode/lxfb.h create mode 100644 drivers/video/fbdev/geode/lxfb_core.c create mode 100644 drivers/video/fbdev/geode/lxfb_ops.c create mode 100644 drivers/video/fbdev/geode/suspend_gx.c create mode 100644 drivers/video/fbdev/geode/video_cs5530.c create mode 100644 drivers/video/fbdev/geode/video_cs5530.h create mode 100644 drivers/video/fbdev/geode/video_gx.c create mode 100644 drivers/video/fbdev/goldfishfb.c create mode 100644 drivers/video/fbdev/grvga.c create mode 100644 drivers/video/fbdev/gxt4500.c create mode 100644 drivers/video/fbdev/hecubafb.c create mode 100644 drivers/video/fbdev/hitfb.c create mode 100644 drivers/video/fbdev/hpfb.c create mode 100644 drivers/video/fbdev/i740_reg.h create mode 100644 drivers/video/fbdev/i740fb.c create mode 100644 drivers/video/fbdev/i810/Makefile create mode 100644 drivers/video/fbdev/i810/i810-i2c.c create mode 100644 drivers/video/fbdev/i810/i810.h create mode 100644 drivers/video/fbdev/i810/i810_accel.c create mode 100644 drivers/video/fbdev/i810/i810_dvt.c create mode 100644 drivers/video/fbdev/i810/i810_gtf.c create mode 100644 drivers/video/fbdev/i810/i810_main.c create mode 100644 drivers/video/fbdev/i810/i810_main.h create mode 100644 drivers/video/fbdev/i810/i810_regs.h create mode 100644 drivers/video/fbdev/imsttfb.c create mode 100644 drivers/video/fbdev/imxfb.c create mode 100644 drivers/video/fbdev/kyro/Makefile create mode 100644 drivers/video/fbdev/kyro/STG4000InitDevice.c create mode 100644 drivers/video/fbdev/kyro/STG4000Interface.h create mode 100644 drivers/video/fbdev/kyro/STG4000OverlayDevice.c create mode 100644 drivers/video/fbdev/kyro/STG4000Ramdac.c create mode 100644 drivers/video/fbdev/kyro/STG4000Reg.h create mode 100644 drivers/video/fbdev/kyro/STG4000VTG.c create mode 100644 drivers/video/fbdev/kyro/fbdev.c create mode 100644 drivers/video/fbdev/leo.c create mode 100644 drivers/video/fbdev/macfb.c create mode 100644 drivers/video/fbdev/macmodes.c create mode 100644 drivers/video/fbdev/macmodes.h create mode 100644 drivers/video/fbdev/matrox/Makefile create mode 100644 drivers/video/fbdev/matrox/g450_pll.c create mode 100644 drivers/video/fbdev/matrox/g450_pll.h create mode 100644 drivers/video/fbdev/matrox/i2c-matroxfb.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_DAC1064.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_DAC1064.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_Ti3026.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_Ti3026.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_accel.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_accel.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_base.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_base.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_crtc2.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_crtc2.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_g450.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_g450.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_maven.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_maven.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_misc.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_misc.h create mode 100644 drivers/video/fbdev/maxinefb.c create mode 100644 drivers/video/fbdev/mb862xx/Makefile create mode 100644 drivers/video/fbdev/mb862xx/mb862xx-i2c.c create mode 100644 drivers/video/fbdev/mb862xx/mb862xx_reg.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb_accel.c create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb_accel.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfbdrv.c create mode 100644 drivers/video/fbdev/metronomefb.c create mode 100644 drivers/video/fbdev/mmp/Kconfig create mode 100644 drivers/video/fbdev/mmp/Makefile create mode 100644 drivers/video/fbdev/mmp/core.c create mode 100644 drivers/video/fbdev/mmp/fb/Kconfig create mode 100644 drivers/video/fbdev/mmp/fb/Makefile create mode 100644 drivers/video/fbdev/mmp/fb/mmpfb.c create mode 100644 drivers/video/fbdev/mmp/fb/mmpfb.h create mode 100644 drivers/video/fbdev/mmp/hw/Kconfig create mode 100644 drivers/video/fbdev/mmp/hw/Makefile create mode 100644 drivers/video/fbdev/mmp/hw/mmp_ctrl.c create mode 100644 drivers/video/fbdev/mmp/hw/mmp_ctrl.h create mode 100644 drivers/video/fbdev/mmp/hw/mmp_spi.c create mode 100644 drivers/video/fbdev/mmp/panel/Kconfig create mode 100644 drivers/video/fbdev/mmp/panel/Makefile create mode 100644 drivers/video/fbdev/mmp/panel/tpo_tj032md01bw.c create mode 100644 drivers/video/fbdev/n411.c create mode 100644 drivers/video/fbdev/neofb.c create mode 100644 drivers/video/fbdev/nvidia/Makefile create mode 100644 drivers/video/fbdev/nvidia/nv_accel.c create mode 100644 drivers/video/fbdev/nvidia/nv_backlight.c create mode 100644 drivers/video/fbdev/nvidia/nv_dma.h create mode 100644 drivers/video/fbdev/nvidia/nv_hw.c create mode 100644 drivers/video/fbdev/nvidia/nv_i2c.c create mode 100644 drivers/video/fbdev/nvidia/nv_local.h create mode 100644 drivers/video/fbdev/nvidia/nv_of.c create mode 100644 drivers/video/fbdev/nvidia/nv_proto.h create mode 100644 drivers/video/fbdev/nvidia/nv_setup.c create mode 100644 drivers/video/fbdev/nvidia/nv_type.h create mode 100644 drivers/video/fbdev/nvidia/nvidia.c create mode 100644 drivers/video/fbdev/ocfb.c create mode 100644 drivers/video/fbdev/offb.c create mode 100644 drivers/video/fbdev/omap/Kconfig create mode 100644 drivers/video/fbdev/omap/Makefile create mode 100644 drivers/video/fbdev/omap/hwa742.c create mode 100644 drivers/video/fbdev/omap/lcd_ams_delta.c create mode 100644 drivers/video/fbdev/omap/lcd_dma.c create mode 100644 drivers/video/fbdev/omap/lcd_dma.h create mode 100644 drivers/video/fbdev/omap/lcd_mipid.c create mode 100644 drivers/video/fbdev/omap/lcd_palmte.c create mode 100644 drivers/video/fbdev/omap/lcdc.c create mode 100644 drivers/video/fbdev/omap/lcdc.h create mode 100644 drivers/video/fbdev/omap/omapfb.h create mode 100644 drivers/video/fbdev/omap/omapfb_main.c create mode 100644 drivers/video/fbdev/omap/sossi.c create mode 100644 drivers/video/fbdev/omap2/Kconfig create mode 100644 drivers/video/fbdev/omap2/Makefile create mode 100644 drivers/video/fbdev/omap2/omapfb/Kconfig create mode 100644 drivers/video/fbdev/omap2/omapfb/Makefile create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/Kconfig create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/Makefile create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c create mode 100644 drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/Kconfig create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/Makefile create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/apply.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/core.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dispc.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dispc.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/display.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dpi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dsi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dss-of.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dss.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dss.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dss_features.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/dss_features.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi_common.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/manager.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/output.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/overlay.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/pll.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/sdi.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/venc.c create mode 100644 drivers/video/fbdev/omap2/omapfb/dss/video-pll.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-main.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb.h create mode 100644 drivers/video/fbdev/omap2/omapfb/vrfb.c create mode 100644 drivers/video/fbdev/p9100.c create mode 100644 drivers/video/fbdev/platinumfb.c create mode 100644 drivers/video/fbdev/platinumfb.h create mode 100644 drivers/video/fbdev/pm2fb.c create mode 100644 drivers/video/fbdev/pm3fb.c create mode 100644 drivers/video/fbdev/pmag-aa-fb.c create mode 100644 drivers/video/fbdev/pmag-ba-fb.c create mode 100644 drivers/video/fbdev/pmagb-b-fb.c create mode 100644 drivers/video/fbdev/ps3fb.c create mode 100644 drivers/video/fbdev/pvr2fb.c create mode 100644 drivers/video/fbdev/pxa168fb.c create mode 100644 drivers/video/fbdev/pxa168fb.h create mode 100644 drivers/video/fbdev/pxa3xx-gcu.c create mode 100644 drivers/video/fbdev/pxa3xx-gcu.h create mode 100644 drivers/video/fbdev/pxa3xx-regs.h create mode 100644 drivers/video/fbdev/pxafb.c create mode 100644 drivers/video/fbdev/pxafb.h create mode 100644 drivers/video/fbdev/q40fb.c create mode 100644 drivers/video/fbdev/riva/Makefile create mode 100644 drivers/video/fbdev/riva/fbdev.c create mode 100644 drivers/video/fbdev/riva/nv_driver.c create mode 100644 drivers/video/fbdev/riva/nv_type.h create mode 100644 drivers/video/fbdev/riva/nvreg.h create mode 100644 drivers/video/fbdev/riva/riva_hw.c create mode 100644 drivers/video/fbdev/riva/riva_hw.h create mode 100644 drivers/video/fbdev/riva/riva_tbl.h create mode 100644 drivers/video/fbdev/riva/rivafb-i2c.c create mode 100644 drivers/video/fbdev/riva/rivafb.h create mode 100644 drivers/video/fbdev/s1d13xxxfb.c create mode 100644 drivers/video/fbdev/s3c-fb.c create mode 100644 drivers/video/fbdev/s3fb.c create mode 100644 drivers/video/fbdev/sa1100fb.c create mode 100644 drivers/video/fbdev/sa1100fb.h create mode 100644 drivers/video/fbdev/savage/Makefile create mode 100644 drivers/video/fbdev/savage/savagefb-i2c.c create mode 100644 drivers/video/fbdev/savage/savagefb.h create mode 100644 drivers/video/fbdev/savage/savagefb_accel.c create mode 100644 drivers/video/fbdev/savage/savagefb_driver.c create mode 100644 drivers/video/fbdev/sbuslib.c create mode 100644 drivers/video/fbdev/sbuslib.h create mode 100644 drivers/video/fbdev/sh7760fb.c create mode 100644 drivers/video/fbdev/sh_mobile_lcdcfb.c create mode 100644 drivers/video/fbdev/sh_mobile_lcdcfb.h create mode 100644 drivers/video/fbdev/simplefb.c create mode 100644 drivers/video/fbdev/sis/300vtbl.h create mode 100644 drivers/video/fbdev/sis/310vtbl.h create mode 100644 drivers/video/fbdev/sis/Makefile create mode 100644 drivers/video/fbdev/sis/init.c create mode 100644 drivers/video/fbdev/sis/init.h create mode 100644 drivers/video/fbdev/sis/init301.c create mode 100644 drivers/video/fbdev/sis/init301.h create mode 100644 drivers/video/fbdev/sis/initdef.h create mode 100644 drivers/video/fbdev/sis/initextlfb.c create mode 100644 drivers/video/fbdev/sis/oem300.h create mode 100644 drivers/video/fbdev/sis/oem310.h create mode 100644 drivers/video/fbdev/sis/sis.h create mode 100644 drivers/video/fbdev/sis/sis_accel.c create mode 100644 drivers/video/fbdev/sis/sis_accel.h create mode 100644 drivers/video/fbdev/sis/sis_main.c create mode 100644 drivers/video/fbdev/sis/sis_main.h create mode 100644 drivers/video/fbdev/sis/vgatypes.h create mode 100644 drivers/video/fbdev/sis/vstruct.h create mode 100644 drivers/video/fbdev/skeletonfb.c create mode 100644 drivers/video/fbdev/sm501fb.c create mode 100644 drivers/video/fbdev/sm712.h create mode 100644 drivers/video/fbdev/sm712fb.c create mode 100644 drivers/video/fbdev/smscufx.c create mode 100644 drivers/video/fbdev/ssd1307fb.c create mode 100644 drivers/video/fbdev/sstfb.c create mode 100644 drivers/video/fbdev/stifb.c create mode 100644 drivers/video/fbdev/sunxvr1000.c create mode 100644 drivers/video/fbdev/sunxvr2500.c create mode 100644 drivers/video/fbdev/sunxvr500.c create mode 100644 drivers/video/fbdev/tcx.c create mode 100644 drivers/video/fbdev/tdfxfb.c create mode 100644 drivers/video/fbdev/tgafb.c create mode 100644 drivers/video/fbdev/tridentfb.c create mode 100644 drivers/video/fbdev/udlfb.c create mode 100644 drivers/video/fbdev/uvesafb.c create mode 100644 drivers/video/fbdev/valkyriefb.c create mode 100644 drivers/video/fbdev/valkyriefb.h create mode 100644 drivers/video/fbdev/vesafb.c create mode 100644 drivers/video/fbdev/vfb.c create mode 100644 drivers/video/fbdev/vga16fb.c create mode 100644 drivers/video/fbdev/via/Makefile create mode 100644 drivers/video/fbdev/via/accel.c create mode 100644 drivers/video/fbdev/via/accel.h create mode 100644 drivers/video/fbdev/via/chip.h create mode 100644 drivers/video/fbdev/via/debug.h create mode 100644 drivers/video/fbdev/via/dvi.c create mode 100644 drivers/video/fbdev/via/dvi.h create mode 100644 drivers/video/fbdev/via/global.c create mode 100644 drivers/video/fbdev/via/global.h create mode 100644 drivers/video/fbdev/via/hw.c create mode 100644 drivers/video/fbdev/via/hw.h create mode 100644 drivers/video/fbdev/via/ioctl.c create mode 100644 drivers/video/fbdev/via/ioctl.h create mode 100644 drivers/video/fbdev/via/lcd.c create mode 100644 drivers/video/fbdev/via/lcd.h create mode 100644 drivers/video/fbdev/via/share.h create mode 100644 drivers/video/fbdev/via/tblDPASetting.c create mode 100644 drivers/video/fbdev/via/tblDPASetting.h create mode 100644 drivers/video/fbdev/via/via-core.c create mode 100644 drivers/video/fbdev/via/via-gpio.c create mode 100644 drivers/video/fbdev/via/via-gpio.h create mode 100644 drivers/video/fbdev/via/via_aux.c create mode 100644 drivers/video/fbdev/via/via_aux.h create mode 100644 drivers/video/fbdev/via/via_aux_ch7301.c create mode 100644 drivers/video/fbdev/via/via_aux_edid.c create mode 100644 drivers/video/fbdev/via/via_aux_sii164.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1621.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1622.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1625.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1631.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1632.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1636.c create mode 100644 drivers/video/fbdev/via/via_clock.c create mode 100644 drivers/video/fbdev/via/via_clock.h create mode 100644 drivers/video/fbdev/via/via_i2c.c create mode 100644 drivers/video/fbdev/via/via_modesetting.c create mode 100644 drivers/video/fbdev/via/via_modesetting.h create mode 100644 drivers/video/fbdev/via/via_utility.c create mode 100644 drivers/video/fbdev/via/via_utility.h create mode 100644 drivers/video/fbdev/via/viafbdev.c create mode 100644 drivers/video/fbdev/via/viafbdev.h create mode 100644 drivers/video/fbdev/via/viamode.c create mode 100644 drivers/video/fbdev/via/viamode.h create mode 100644 drivers/video/fbdev/via/vt1636.c create mode 100644 drivers/video/fbdev/via/vt1636.h create mode 100644 drivers/video/fbdev/vt8500lcdfb.c create mode 100644 drivers/video/fbdev/vt8500lcdfb.h create mode 100644 drivers/video/fbdev/vt8623fb.c create mode 100644 drivers/video/fbdev/wm8505fb.c create mode 100644 drivers/video/fbdev/wm8505fb_regs.h create mode 100644 drivers/video/fbdev/wmt_ge_rops.c create mode 100644 drivers/video/fbdev/wmt_ge_rops.h create mode 100644 drivers/video/fbdev/xen-fbfront.c create mode 100644 drivers/video/fbdev/xilinxfb.c (limited to 'drivers/video/fbdev') diff --git a/drivers/video/fbdev/68328fb.c b/drivers/video/fbdev/68328fb.c new file mode 100644 index 000000000..c24156eb3 --- /dev/null +++ b/drivers/video/fbdev/68328fb.c @@ -0,0 +1,482 @@ +/* + * linux/drivers/video/68328fb.c -- Low level implementation of the + * mc68x328 LCD frame buffer device + * + * Copyright (C) 2003 Georges Menie + * + * This driver assumes an already configured controller (e.g. from config.c) + * Keep the code clean of board specific initialization. + * + * This code has not been tested with colors, colormap management functions + * are minimal (no colormap data written to the 68328 registers...) + * + * initial version of this driver: + * Copyright (C) 1998,1999 Kenneth Albanowski , + * The Silver Hammer Group, Ltd. + * + * this version is based on : + * + * linux/drivers/video/vfb.c -- Virtual frame buffer device + * + * Copyright (C) 2002 James Simmons + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_M68VZ328) +#include +#elif defined(CONFIG_M68EZ328) +#include +#elif defined(CONFIG_M68328) +#include +#else +#error wrong architecture for the MC68x328 frame buffer device +#endif + +static u_long videomemory; +static u_long videomemorysize; + +static struct fb_info fb_info; +static u32 mc68x328fb_pseudo_palette[16]; + +static struct fb_var_screeninfo mc68x328fb_default __initdata = { + .red = { 0, 8, 0 }, + .green = { 0, 8, 0 }, + .blue = { 0, 8, 0 }, + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static const struct fb_fix_screeninfo mc68x328fb_fix __initconst = { + .id = "68328fb", + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE, +}; + + /* + * Interface used by the world + */ +static int mc68x328fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int mc68x328fb_set_par(struct fb_info *info); +static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma); + +static const struct fb_ops mc68x328fb_ops = { + .owner = THIS_MODULE, + __FB_DEFAULT_IOMEM_OPS_RDWR, + .fb_check_var = mc68x328fb_check_var, + .fb_set_par = mc68x328fb_set_par, + .fb_setcolreg = mc68x328fb_setcolreg, + .fb_pan_display = mc68x328fb_pan_display, + __FB_DEFAULT_IOMEM_OPS_DRAW, + .fb_mmap = mc68x328fb_mmap, +}; + + /* + * Internal routines + */ + +static u_long get_line_length(int xres_virtual, int bpp) +{ + u_long length; + + length = xres_virtual * bpp; + length = (length + 31) & ~31; + length >>= 3; + return (length); +} + + /* + * Setting the video mode has been split into two parts. + * First part, xxxfb_check_var, must not write anything + * to hardware, it should only verify and adjust var. + * This means it doesn't alter par but it does use hardware + * data from it to check this var. + */ + +static int mc68x328fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u_long line_length; + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + /* + * Some very basic checks + */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + if (var->bits_per_pixel <= 1) + var->bits_per_pixel = 1; + else if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + if (var->xres_virtual < var->xoffset + var->xres) + var->xres_virtual = var->xoffset + var->xres; + if (var->yres_virtual < var->yoffset + var->yres) + var->yres_virtual = var->yoffset + var->yres; + + /* + * Memory limit + */ + line_length = + get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > videomemorysize) + return -ENOMEM; + + /* + * Now that we checked it we alter var. The reason being is that the video + * mode passed in might not work but slight changes to it might make it + * work. This way we let the user know what is acceptable. + */ + switch (var->bits_per_pixel) { + case 1: + var->red.offset = 0; + var->red.length = 1; + var->green.offset = 0; + var->green.length = 1; + var->blue.offset = 0; + var->blue.length = 1; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGBA 5551 */ + if (var->transp.length) { + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + break; + case 24: /* RGB 888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGBA 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + + return 0; +} + +/* This routine actually sets the video mode. It's in here where we + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. + */ +static int mc68x328fb_set_par(struct fb_info *info) +{ + info->fix.line_length = get_line_length(info->var.xres_virtual, + info->var.bits_per_pixel); + return 0; +} + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return 1; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of RAMDAC + * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = RAMDAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains width of DAC + * cmap is not used + * RAMDAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use DAC. Usually 3 are present. + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return 1; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + switch (info->var.bits_per_pixel) { + case 8: + break; + case 16: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + return 0; +} + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 + || var->yoffset >= info->var.yres_virtual + || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + } + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + /* + * Most drivers don't need their own mmap function + */ + +static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ +#ifndef MMU + /* this is uClinux (no MMU) specific code */ + + vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_start = videomemory; + + return 0; +#else + return -EINVAL; +#endif +} + +static int __init mc68x328fb_setup(char *options) +{ + if (!options || !*options) + return 1; + return 1; +} + + /* + * Initialisation + */ + +static int __init mc68x328fb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("68328fb", &option)) + return -ENODEV; + mc68x328fb_setup(option); +#endif + /* + * initialize the default mode from the LCD controller registers + */ + mc68x328fb_default.xres = LXMAX; + mc68x328fb_default.yres = LYMAX+1; + mc68x328fb_default.xres_virtual = mc68x328fb_default.xres; + mc68x328fb_default.yres_virtual = mc68x328fb_default.yres; + mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01); + videomemory = LSSA; + videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 * + mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel; + + fb_info.screen_base = (void *)videomemory; + fb_info.fbops = &mc68x328fb_ops; + fb_info.var = mc68x328fb_default; + fb_info.fix = mc68x328fb_fix; + fb_info.fix.smem_start = videomemory; + fb_info.fix.smem_len = videomemorysize; + fb_info.fix.line_length = + get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); + fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? + FB_VISUAL_MONO10 : FB_VISUAL_PSEUDOCOLOR; + if (fb_info.var.bits_per_pixel == 1) { + fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; + fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; + } + fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; + fb_info.flags = FBINFO_HWACCEL_YPAN; + + if (fb_alloc_cmap(&fb_info.cmap, 256, 0)) + return -ENOMEM; + + if (register_framebuffer(&fb_info) < 0) { + fb_dealloc_cmap(&fb_info.cmap); + return -EINVAL; + } + + fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id); + fb_info(&fb_info, "%dx%dx%d at 0x%08lx\n", + mc68x328fb_default.xres_virtual, + mc68x328fb_default.yres_virtual, + 1 << mc68x328fb_default.bits_per_pixel, videomemory); + + return 0; +} + +module_init(mc68x328fb_init); + +#ifdef MODULE + +static void __exit mc68x328fb_cleanup(void) +{ + unregister_framebuffer(&fb_info); + fb_dealloc_cmap(&fb_info.cmap); +} + +module_exit(mc68x328fb_cleanup); + +MODULE_LICENSE("GPL"); +#endif /* MODULE */ diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig new file mode 100644 index 000000000..e8cd8cb76 --- /dev/null +++ b/drivers/video/fbdev/Kconfig @@ -0,0 +1,1805 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# fbdev configuration +# + +menuconfig FB + tristate "Support for frame buffer device drivers" + select FB_CORE + select FB_NOTIFY + help + The frame buffer device provides an abstraction for the graphics + hardware. It represents the frame buffer of some video hardware and + allows application software to access the graphics hardware through + a well-defined interface, so the software doesn't need to know + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + + The device is accessed through special device nodes, usually located + in the /dev directory, i.e. /dev/fb*. + + You need an utility program called fbset to make full use of frame + buffer devices. Please read + and the Framebuffer-HOWTO at + for more + information. + + This enables support for native frame buffer device (fbdev) drivers. + + The DRM subsystem provides support for emulated frame buffer devices + on top of KMS drivers, but this option allows legacy fbdev drivers to + be enabled as well. + + Say Y here and to the driver for your graphics board below if you + are compiling a kernel for a non-x86 architecture. + + If you are compiling for the x86 architecture, you can say Y if you + want to play with it, but it is not essential. Please note that + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. + +config FB_HECUBA + tristate + depends on FB + select FB_SYSMEM_HELPERS_DEFERRED + +config FB_SVGALIB + tristate + depends on FB + help + Common utility functions useful to fbdev drivers of VGA-based + cards. + +config FB_MACMODES + tristate + depends on FB + +config FB_GRVGA + tristate "Aeroflex Gaisler framebuffer support" + depends on FB && SPARC + select FB_IOMEM_HELPERS + help + This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler. + +config FB_CIRRUS + tristate "Cirrus Logic support" + depends on FB && (ZORRO || PCI) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + + If you have a PCI-based system, this enables support for these + chips: GD-543x, GD-544x, GD-5480. + + Please read the file . + + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. + +config FB_PM2 + tristate "Permedia2 support" + depends on FB && ((AMIGA && BROKEN) || PCI) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for cards based on + the 3D Labs Permedia, Permedia 2 and Permedia 2V chips. + The driver was tested on the following cards: + Diamond FireGL 1000 PRO AGP + ELSA Gloria Synergy PCI + Appian Jeronimo PRO (both heads) PCI + 3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI + Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC + ASK Graphic Blaster Exxtreme AGP + + To compile this driver as a module, choose M here: the + module will be called pm2fb. + +config FB_PM2_FIFO_DISCONNECT + bool "enable FIFO disconnect feature" + depends on FB_PM2 && PCI + help + Support the Permedia2 FIFO disconnect feature. + +config FB_ACORN + bool "Acorn VIDC support" + depends on (FB = y) && ARM && ARCH_ACORN + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for the Acorn VIDC graphics + hardware found in Acorn RISC PCs and other ARM-based machines. If + unsure, say N. + +config FB_CLPS711X + tristate "CLPS711X LCD support" + depends on FB && (ARCH_CLPS711X || COMPILE_TEST) + depends on LCD_CLASS_DEVICE + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + help + Say Y to enable the Framebuffer driver for the Cirrus Logic + CLPS711X CPUs. + +config FB_SA1100 + bool "SA-1100 LCD support" + depends on (FB = y) && ARM && ARCH_SA1100 + select FB_IOMEM_HELPERS + help + This is a framebuffer device for the SA-1100 LCD Controller. + See for information on framebuffer + devices. + + If you plan to use the LCD display with your SA-1100 system, say + Y here. + +config FB_IMX + tristate "Freescale i.MX1/21/25/27 LCD support" + depends on FB && HAVE_CLK && HAS_IOMEM + depends on ARCH_MXC || COMPILE_TEST + depends on LCD_CLASS_DEVICE + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + +config FB_CYBER2000 + tristate "CyberPro 2000/2010/5000 support" + depends on FB && PCI && HAS_IOPORT && (BROKEN || !SPARC64) + select FB_IOMEM_HELPERS + help + This enables support for the Integraphics CyberPro 20x0 and 5000 + VGA chips used in the Rebel.com Netwinder and other machines. + Say Y if you have a NetWinder or a graphics card containing this + device, otherwise say N. + +config FB_CYBER2000_DDC + bool "DDC for CyberPro support" + depends on FB_CYBER2000 + select FB_DDC + default y + help + Say Y here if you want DDC support for your CyberPro graphics + card. This is only I2C bus support, driver does not use EDID. + +config FB_CYBER2000_I2C + bool "CyberPro 2000/2010/5000 I2C support" + depends on FB_CYBER2000 && I2C && ARCH_NETWINDER + depends on I2C=y || FB_CYBER2000=m + select I2C_ALGOBIT + help + Enable support for the I2C video decoder interface on the + Integraphics CyberPro 20x0 and 5000 VGA chips. This is used + on the Netwinder machines for the SAA7111 video capture. + +config FB_APOLLO + bool + depends on (FB = y) && APOLLO + default y + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + +config FB_Q40 + bool + depends on (FB = y) && Q40 + default y + select FB_IOMEM_HELPERS + +config FB_AMIGA + tristate "Amiga native chipset support" + depends on FB && AMIGA + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the builtin graphics + chipset found in Amigas. + + To compile this driver as a module, choose M here: the + module will be called amifb. + +config FB_AMIGA_OCS + bool "Amiga OCS chipset support" + depends on FB_AMIGA + help + This enables support for the original Agnus and Denise video chips, + found in the Amiga 1000 and most A500's and A2000's. If you intend + to run Linux on any of these systems, say Y; otherwise say N. + +config FB_AMIGA_ECS + bool "Amiga ECS chipset support" + depends on FB_AMIGA + help + This enables support for the Enhanced Chip Set, found in later + A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If + you intend to run Linux on any of these systems, say Y; otherwise + say N. + +config FB_AMIGA_AGA + bool "Amiga AGA chipset support" + depends on FB_AMIGA + help + This enables support for the Advanced Graphics Architecture (also + known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T + and CD32. If you intend to run Linux on any of these systems, say Y; + otherwise say N. + +config FB_FM2 + bool "Amiga FrameMaster II/Rainbow II support" + depends on (FB = y) && ZORRO + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for the Amiga FrameMaster + card from BSC (exhibited 1992 but not shipped as a CBM product). + +config FB_ARC + tristate "Arc Monochrome LCD board support" + depends on FB && HAS_IOPORT && (X86 || COMPILE_TEST) + select FB_SYSMEM_HELPERS_DEFERRED + help + This enables support for the Arc Monochrome LCD board. The board + is based on the KS-108 lcd controller and is typically a matrix + of 2*n chips. This driver was tested with a 128x64 panel. This + driver supports it for use with x86 SBCs through a 16 bit GPIO + interface (8 bit data, 8 bit control). If you anticipate using + this driver, say Y or M; otherwise say N. You must specify the + GPIO IO address to be used for setting control and data. + +config FB_ATARI + bool "Atari native chipset support" + depends on (FB = y) && ATARI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. + +config FB_OF + tristate "Open Firmware frame buffer device support" + depends on FB && PPC && (!PPC_PSERIES || PCI) + depends on !DRM_OFDRM + select APERTURE_HELPERS + select FB_IOMEM_HELPERS + select FB_MACMODES + help + Say Y if you want support with Open Firmware for your graphics + board. + +config FB_CONTROL + bool "Apple \"control\" display support" + depends on (FB = y) && ((PPC_PMAC && PPC32) || COMPILE_TEST) + select FB_IOMEM_HELPERS + select FB_MACMODES + help + This driver supports a frame buffer for the graphics adapter in the + Power Macintosh 7300 and others. + +config FB_PLATINUM + bool "Apple \"platinum\" display support" + depends on (FB = y) && PPC_PMAC && PPC32 + select FB_IOMEM_HELPERS + select FB_MACMODES + help + This driver supports a frame buffer for the "platinum" graphics + adapter in some Power Macintoshes. + +config FB_VALKYRIE + bool "Apple \"valkyrie\" display support" + depends on (FB = y) && (MAC || (PPC_PMAC && PPC32)) + select FB_IOMEM_HELPERS + select FB_MACMODES + help + This driver supports a frame buffer for the "valkyrie" graphics + adapter in some Power Macintoshes. + +config FB_CT65550 + bool "Chips 65550 display support" + depends on (FB = y) && PPC32 && PCI + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for the Chips & Technologies + 65550 graphics chip in PowerBooks. + +config FB_ASILIANT + bool "Asiliant (Chips) 69000 display support" + depends on (FB = y) && PCI + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for the Asiliant 69030 chipset + +config FB_IMSTT + bool "IMS Twin Turbo display support" + depends on (FB = y) && PCI + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MACMODES if PPC_PMAC + help + The IMS Twin Turbo is a PCI-based frame buffer card bundled with + many Macintosh and compatible computers. + +config FB_VGA16 + tristate "VGA 16-color graphics support" + depends on FB && X86 + select APERTURE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select VGASTATE + select FONT_8x16 if FRAMEBUFFER_CONSOLE + help + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + + To compile this driver as a module, choose M here: the + module will be called vga16fb. + +config FB_STI + tristate "HP STI frame buffer device support" + depends on FB && PARISC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select STI_CORE + default y + help + Enabling this option will implement the linux framebuffer device + using calls to the STI BIOS routines for initialisation. + + If you enable this option, you will get a planar framebuffer device + /dev/fb which will work on the most common HP graphic cards of the + NGLE family, including the artist chips (in the 7xx and Bxxx series), + HCRX, HCRX24, CRX, CRX24 and VisEG series. + + It is safe to enable this option, so you should probably say "Y". + +config FB_MAC + bool "Generic Macintosh display support" + depends on (FB = y) && MAC + select FB_IOMEM_HELPERS + select FB_MACMODES + +config FB_HP300 + bool + depends on (FB = y) && DIO + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + default y + +config FB_TGA + tristate "TGA/SFB+ framebuffer support" + depends on FB + depends on PCI || TC + depends on ALPHA || TC + select BITREVERSE + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for generic TGA and SFB+ + graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards, + also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3 + TURBOchannel cards, also known as PMAGD-A, -B and -C. + + Due to hardware limitations ZLX-E2 and E3 cards are not supported + for DECstation 5000/200 systems. Additionally due to firmware + limitations these cards may cause troubles with booting DECstation + 5000/240 and /260 systems, but are fully supported under Linux if + you manage to get it going. ;-) + + Say Y if you have one of those. + +config FB_UVESA + tristate "Userspace VESA VGA graphics support" + depends on FB && CONNECTOR + depends on !UML + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + help + This is the frame buffer driver for generic VBE 2.0 compliant + graphic cards. It can also take advantage of VBE 3.0 features, + such as refresh rate adjustment. + + This driver generally provides more features than vesafb but + requires a userspace helper application called 'v86d'. See + for more information. + + If unsure, say N. + +config FB_VESA + bool "VESA VGA graphics support" + depends on (FB = y) && X86 + select APERTURE_HELPERS + select FB_IOMEM_HELPERS + select SYSFB + help + This is the frame buffer device driver for generic VESA 2.0 + compliant graphic cards. The older VESA 1.2 cards are not supported. + You will get a boot time penguin logo at no additional cost. Please + read . If unsure, say Y. + +config FB_EFI + bool "EFI-based Framebuffer Support" + depends on (FB = y) && EFI + select APERTURE_HELPERS + select DRM_PANEL_ORIENTATION_QUIRKS + select FB_IOMEM_HELPERS + select SYSFB + help + This is the EFI frame buffer device driver. If the firmware on + your platform is EFI 1.10 or UEFI 2.0, select Y to add support for + using the EFI framebuffer as your console. + +config FB_N411 + tristate "N411 Apollo/Hecuba devkit support" + depends on FB && X86 && MMU + select FB_HECUBA + help + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. + +config FB_GBE + bool "SGI Graphics Backend frame buffer support" + depends on (FB = y) && HAS_IOMEM + depends on SGI_IP32 || COMPILE_TEST + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for SGI Graphics Backend. + This chip is used in SGI O2 and Visual Workstation 320/540. + +config FB_GBE_MEM + int "Video memory size in MB" + depends on FB_GBE + default 4 + help + This is the amount of memory reserved for the framebuffer, + which can be any value between 1MB and 8MB. + +config FB_SBUS + bool "SBUS and UPA framebuffers" + depends on (FB = y) && SPARC + help + Say Y if you want support for SBUS or UPA based frame buffer device. + +config FB_SBUS_HELPERS + bool + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + +config FB_BW2 + bool "BWtwo support" + depends on (FB = y) && (SPARC && FB_SBUS) + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the BWtwo frame buffer. + +config FB_CG3 + bool "CGthree support" + depends on (FB = y) && (SPARC && FB_SBUS) + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the CGthree frame buffer. + +config FB_CG6 + bool "CGsix (GX,TurboGX) support" + depends on (FB = y) && (SPARC && FB_SBUS) + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the CGsix (GX, TurboGX) + frame buffer. + +config FB_FFB + bool "Creator/Creator3D/Elite3D support" + depends on FB_SBUS && SPARC64 + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the Creator, Creator3D, + and Elite3D graphics boards. + +config FB_TCX + bool "TCX (SS4/SS5 only) support" + depends on FB_SBUS + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the TCX 24/8bit frame + buffer. + +config FB_CG14 + bool "CGfourteen (SX) support" + depends on FB_SBUS + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the CGfourteen frame + buffer on Desktop SPARCsystems with the SX graphics option. + +config FB_P9100 + bool "P9100 (Sparcbook 3 only) support" + depends on FB_SBUS + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the P9100 card + supported on Sparcbook 3 machines. + +config FB_LEO + bool "Leo (ZX) support" + depends on FB_SBUS + select FB_SBUS_HELPERS + help + This is the frame buffer device driver for the SBUS-based Sun ZX + (leo) frame buffer cards. + +config FB_XVR500 + bool "Sun XVR-500 3DLABS Wildcat support" + depends on (FB = y) && PCI && SPARC64 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the framebuffer device for the Sun XVR-500 and similar + graphics cards based upon the 3DLABS Wildcat chipset. The driver + only works on sparc64 systems where the system firmware has + mostly initialized the card already. It is treated as a + completely dumb framebuffer device. + +config FB_XVR2500 + bool "Sun XVR-2500 3DLABS Wildcat support" + depends on (FB = y) && PCI && SPARC64 + select FB_IOMEM_HELPERS + help + This is the framebuffer device for the Sun XVR-2500 and similar + graphics cards based upon the 3DLABS Wildcat chipset. The driver + only works on sparc64 systems where the system firmware has + mostly initialized the card already. It is treated as a + completely dumb framebuffer device. + +config FB_XVR1000 + bool "Sun XVR-1000 support" + depends on (FB = y) && SPARC64 + select FB_IOMEM_HELPERS + help + This is the framebuffer device for the Sun XVR-1000 and similar + graphics cards. The driver only works on sparc64 systems where + the system firmware has mostly initialized the card already. It + is treated as a completely dumb framebuffer device. + +config FB_PVR2 + tristate "NEC PowerVR 2 display support" + depends on FB && HAS_IOMEM + depends on SH_DREAMCAST || COMPILE_TEST + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + Say Y here if you have a PowerVR 2 card in your box. If you plan to + run linux on your Dreamcast, you will have to say Y here. + This driver may or may not work on other PowerVR 2 cards, but is + totally untested. Use at your own risk. If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pvr2fb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=pvr2:XXX", where + the meaning of XXX can be found at the end of the main source file + (). Please see the file + . + +config FB_OPENCORES + tristate "OpenCores VGA/LCD core 2.0 framebuffer support" + depends on FB && HAS_DMA + select FB_IOMEM_HELPERS + help + This enables support for the OpenCores VGA/LCD core. + + The OpenCores VGA/LCD core is typically used together with + softcore CPUs (e.g. OpenRISC or Microblaze) or hard processor + systems (e.g. Altera socfpga or Xilinx Zynq) on FPGAs. + + The source code and specification for the core is available at + + +config FB_S1D13XXX + tristate "Epson S1D13XXX framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + Support for S1D13XXX framebuffer device family (currently only + working with S1D13806). Product specs at + + +config FB_ATMEL + tristate "AT91 LCD Controller support" + depends on FB && OF && HAVE_CLK && HAS_IOMEM + depends on BACKLIGHT_CLASS_DEVICE + depends on HAVE_FB_ATMEL || COMPILE_TEST + select FB_BACKLIGHT + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + help + This enables support for the AT91 LCD Controller. + +config FB_NVIDIA + tristate "nVidia Framebuffer Support" + depends on FB && PCI && HAS_IOPORT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select BITREVERSE + select VGASTATE + help + This driver supports graphics boards with the nVidia chips, from TNT + through early GeForce generations (NV4–NV2x: Twintor, Twintor2, Celsius, + Kelvin). + Later architectures (Rankine and newer) are not reliably supported. + For very old chipsets, such as the RIVA128, use rivafb. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called nvidiafb. + +config FB_NVIDIA_I2C + bool "Enable DDC Support" + depends on FB_NVIDIA + select FB_DDC + help + This enables I2C support for nVidia Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_NVIDIA_DEBUG + bool "Lots of debug output" + depends on FB_NVIDIA + help + Say Y here if you want the nVidia driver to output all sorts + of debugging information to provide to the maintainer when + something goes wrong. + +config FB_NVIDIA_BACKLIGHT + bool "Support for backlight control" + depends on FB_NVIDIA + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_NVIDIA + select FB_BACKLIGHT + default y + help + Say Y here if you want to control the backlight of your display. + +config FB_RIVA + tristate "nVidia Riva support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + select BITREVERSE + select VGASTATE + help + This driver supports graphics boards with the nVidia Riva/Geforce + chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called rivafb. + +config FB_RIVA_I2C + bool "Enable DDC Support" + depends on FB_RIVA + select FB_DDC + help + This enables I2C support for nVidia Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_RIVA_DEBUG + bool "Lots of debug output" + depends on FB_RIVA + help + Say Y here if you want the Riva driver to output all sorts + of debugging information to provide to the maintainer when + something goes wrong. + +config FB_RIVA_BACKLIGHT + bool "Support for backlight control" + depends on FB_RIVA + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_RIVA + select FB_BACKLIGHT + default y + help + Say Y here if you want to control the backlight of your display. + +config FB_I740 + tristate "Intel740 support" + depends on FB && PCI + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + select VGASTATE + select FB_DDC + help + This driver supports graphics cards based on Intel740 chip. + +config FB_I810 + tristate "Intel 810/815 support" + depends on FB && PCI && X86_32 && AGP_INTEL + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + select VGASTATE + help + This driver supports the on-board graphics built in to the Intel 810 + and 815 chipsets. Say Y if you have and plan to use such a board. + + To compile this driver as a module, choose M here: the + module will be called i810fb. + + For more information, please read + + +config FB_I810_GTF + bool "use VESA Generalized Timing Formula" + depends on FB_I810 + help + If you say Y, then the VESA standard, Generalized Timing Formula + or GTF, will be used to calculate the required video timing values + per video mode. Since the GTF allows nondiscrete timings + (nondiscrete being a range of values as opposed to discrete being a + set of values), you'll be able to use any combination of horizontal + and vertical resolutions, and vertical refresh rates without having + to specify your own timing parameters. This is especially useful + to maximize the performance of an aging display, or if you just + have a display with nonstandard dimensions. A VESA compliant + monitor is recommended, but can still work with non-compliant ones. + If you need or want this, then select this option. The timings may + not be compliant with Intel's recommended values. Use at your own + risk. + + If you say N, the driver will revert to discrete video timings + using a set recommended by Intel in their documentation. + + If unsure, say N. + +config FB_I810_I2C + bool "Enable DDC Support" + depends on FB_I810 && FB_I810_GTF + select FB_DDC + help + Add DDC/I2C support for i810fb. This will allow the driver to get + display information, especially for monitors with fickle timings. + + If unsure, say Y. + +config FB_MATROX + tristate "Matrox acceleration" + depends on FB && PCI + depends on FB_TILEBLITTING + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MACMODES if PPC_PMAC + help + Say Y here if you have a Matrox Millennium, Matrox Millennium II, + Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, + Matrox G400, G450 or G550 card in your box. + + To compile this driver as a module, choose M here: the + module will be called matroxfb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=matroxfb:XXX", and + are described in . + +config FB_MATROX_MILLENIUM + bool "Millennium I/II support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Millennium or Matrox Millennium II + video card. If you select "Advanced lowlevel driver options" below, + you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp + packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can + also use font widths different from 8. + +config FB_MATROX_MYSTIQUE + bool "Mystique support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Mystique or Matrox Mystique 220 + video card. If you select "Advanced lowlevel driver options" below, + you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp + packed pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + +config FB_MATROX_G + bool "G100/G200/G400/G450/G550 support" + depends on FB_MATROX + help + Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based + video card. If you select "Advanced lowlevel driver options", you + should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed + pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + + If you need support for G400 secondary head, you must say Y to + "Matrox I2C support" and "G400 second head support" right below. + G450/G550 secondary head and digital output are supported without + additional modules. + + The driver starts in monitor mode. You must use the matroxset tool + (available at ) to + swap primary and secondary head outputs, or to change output mode. + Secondary head driver always start in 640x480 resolution and you + must use fbset to change it. + + Do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + + G450/G550 hardware can display TV picture only from secondary CRTC, + and it performs no scaling, so picture must have 525 or 625 lines. + +config FB_MATROX_I2C + tristate "Matrox I2C support" + depends on FB_MATROX + select FB_DDC + help + This drivers creates I2C buses which are needed for accessing the + DDC (I2C) bus present on all Matroxes, an I2C bus which + interconnects Matrox optional devices, like MGA-TVO on G200 and + G400, and the secondary head DDC bus, present on G400 only. + + You can say Y or M here if you want to experiment with monitor + detection code. You must say Y or M here if you want to use either + second head of G400 or MGA-TVO on G200 or G400. + + If you compile it as module, it will create a module named + i2c-matroxfb. + +config FB_MATROX_MAVEN + tristate "G400 second head support" + depends on FB_MATROX_G && FB_MATROX_I2C + select FB_IOMEM_HELPERS + help + WARNING !!! This support does not work with G450 !!! + + Say Y or M here if you want to use a secondary head (meaning two + monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary + head is not compatible with accelerated XFree 3.3.x SVGA servers - + secondary head output is blanked while you are in X. With XFree + 3.9.17 preview you can use both heads if you use SVGA over fbdev or + the fbdev driver on first head and the fbdev driver on second head. + + If you compile it as module, two modules are created, + matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for + both G200 and G400, matroxfb_crtc2 is needed only by G400. You must + also load i2c-matroxfb to get it to run. + + The driver starts in monitor mode and you must use the matroxset + tool (available at + ) to switch it to + PAL or NTSC or to swap primary and secondary head outputs. + Secondary head driver also always start in 640x480 resolution, you + must use fbset to change it. + + Also do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + +config FB_RADEON + tristate "ATI Radeon display support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MACMODES if PPC + select FB_MODE_HELPERS + help + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + +config FB_RADEON_I2C + bool "DDC/I2C for ATI Radeon support" + depends on FB_RADEON + select FB_DDC + default y + help + Say Y here if you want DDC/I2C support for your Radeon board. + +config FB_RADEON_BACKLIGHT + bool "Support for backlight control" + depends on FB_RADEON + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_RADEON + select FB_BACKLIGHT + default y + help + Say Y here if you want to control the backlight of your display. + +config FB_RADEON_DEBUG + bool "Lots of debug output from Radeon driver" + depends on FB_RADEON + help + Say Y here if you want the Radeon driver to output all sorts + of debugging information to provide to the maintainer when + something goes wrong. + +config FB_ATY128 + tristate "ATI Rage128 display support" + depends on FB && PCI + select FB_IOMEM_HELPERS + select FB_MACMODES if PPC_PMAC + help + This driver supports graphics boards with the ATI Rage128 chips. + Say Y if you have such a graphics board and read + . + + To compile this driver as a module, choose M here: the + module will be called aty128fb. + +config FB_ATY128_BACKLIGHT + bool "Support for backlight control" + depends on FB_ATY128 + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_ATY128 + select FB_BACKLIGHT + default y + help + Say Y here if you want to control the backlight of your display. + +config FB_ATY + tristate "ATI Mach64 display support" if PCI || ATARI + depends on FB && !SPARC32 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MACMODES if PPC + select FB_ATY_CT if SPARC64 && PCI + help + This driver supports graphics boards with the ATI Mach64 chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called atyfb. + +config FB_ATY_CT + bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" + depends on PCI && FB_ATY + help + Say Y here to support use of ATI's 64-bit Rage boards (or other + boards based on the Mach64 CT, VT, GT, and LT chipsets) as a + framebuffer device. The ATI product support page for these boards + is at . + +config FB_ATY_GENERIC_LCD + bool "Mach64 generic LCD support" + depends on FB_ATY_CT + help + Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility, + Rage XC, or Rage XL chipset. + +config FB_ATY_GX + bool "Mach64 GX support" if PCI + depends on FB_ATY + default y if ATARI + help + Say Y here to support use of the ATI Mach64 Graphics Expression + board (or other boards based on the Mach64 GX chipset) as a + framebuffer device. The ATI product support page for these boards + is at + . + +config FB_ATY_BACKLIGHT + bool "Support for backlight control" + depends on FB_ATY + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_ATY + select FB_BACKLIGHT + default y + help + Say Y here if you want to control the backlight of your display. + +config FB_S3 + tristate "S3 Trio/Virge support" + depends on FB && PCI && HAS_IOPORT + depends on FB_TILEBLITTING + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_SVGALIB + select VGASTATE + select FB_CFB_REV_PIXELS_IN_BYTE + select FONT_8x16 if FRAMEBUFFER_CONSOLE + help + Driver for graphics boards with S3 Trio / S3 Virge chip. + +config FB_S3_DDC + bool "DDC for S3 support" + depends on FB_S3 + select FB_DDC + default y + help + Say Y here if you want DDC support for your S3 graphics card. + +config FB_SAVAGE + tristate "S3 Savage support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + select VGASTATE + help + This driver supports notebooks and computers with S3 Savage PCI/AGP + chips. + + Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here; the module + will be called savagefb. + +config FB_SAVAGE_I2C + bool "Enable DDC2 Support" + depends on FB_SAVAGE + select FB_DDC + help + This enables I2C support for S3 Savage Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_SAVAGE_ACCEL + bool "Enable Console Acceleration" + depends on FB_SAVAGE + help + This option will compile in console acceleration support. If + the resulting framebuffer console has bothersome glitches, then + choose N here. + +config FB_SIS + tristate "SiS/XGI display support" + depends on FB && PCI && HAS_IOPORT + select BOOT_VESA_SUPPORT if FB_SIS = y + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_SIS_300 if !FB_SIS_315 + help + This is the frame buffer device driver for the SiS 300, 315, 330 + and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. + Specs available at and . + + To compile this driver as a module, choose M here; the module + will be called sisfb. + +config FB_SIS_300 + bool "SiS 300 series support" + depends on FB_SIS + help + Say Y here to support use of the SiS 300/305, 540, 630 and 730. + +config FB_SIS_315 + bool "SiS 315/330/340 series and XGI support" + depends on FB_SIS + help + Say Y here to support use of the SiS 315, 330 and 340 series + (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well + as XGI V3XT, V5, V8 and Z7. + +config FB_VIA + tristate "VIA UniChrome (Pro) and Chrome9 display support" + depends on FB && PCI && GPIOLIB && I2C && HAS_IOPORT && (X86 || COMPILE_TEST) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select I2C_ALGOBIT + help + This is the frame buffer device driver for Graphics chips of VIA + UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ + CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896 + /P4M900,VX800) + Say Y if you have a VIA UniChrome graphics board. + + To compile this driver as a module, choose M here: the + module will be called viafb. + +if FB_VIA + +config FB_VIA_DIRECT_PROCFS + bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)" + help + Allow direct hardware access to some output registers via procfs. + This is dangerous but may provide the only chance to get the + correct output device configuration. + Its use is strongly discouraged. + +config FB_VIA_X_COMPATIBILITY + bool "X server compatibility" + help + This option reduces the functionality (power saving, ...) of the + framebuffer to avoid negative impact on the OpenChrome X server. + If you use any X server other than fbdev you should enable this + otherwise it should be safe to disable it and allow using all + features. + +endif + +config FB_NEOMAGIC + tristate "NeoMagic display support" + depends on FB && PCI && HAS_IOPORT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + select VGASTATE + help + This driver supports notebooks with NeoMagic PCI chips. + Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here: the + module will be called neofb. + +config FB_KYRO + tristate "IMG Kyro support" + depends on FB && PCI + select FB_IOMEM_HELPERS + help + Say Y here if you have a STG4000 / Kyro / PowerVR 3 based + graphics board. + + To compile this driver as a module, choose M here: the + module will be called kyrofb. + +config FB_3DFX + tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support" + depends on FB && PCI && HAS_IOPORT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + help + This driver supports graphics boards with the 3Dfx Banshee, + Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have + such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tdfxfb. + +config FB_3DFX_ACCEL + bool "3Dfx Acceleration functions" + depends on FB_3DFX + help + This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer + device driver with acceleration functions. + +config FB_3DFX_I2C + bool "Enable DDC/I2C support" + depends on FB_3DFX + select FB_DDC + default y + help + Say Y here if you want DDC/I2C support for your 3dfx Voodoo3. + +config FB_VOODOO1 + tristate "3Dfx Voodoo Graphics (sst1) support" + depends on FB && PCI + select FB_IOMEM_HELPERS + help + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Voodoo2 (cvg) based graphics card. + + To compile this driver as a module, choose M here: the + module will be called sstfb. + + WARNING: Do not use any application that uses the 3D engine + (namely glide) while using this driver. + Please read the for supported + options and other important info support. + +config FB_VT8623 + tristate "VIA VT8623 support" + depends on FB && PCI && HAS_IOPORT + depends on FB_TILEBLITTING + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_SVGALIB + select VGASTATE + select FONT_8x16 if FRAMEBUFFER_CONSOLE + help + Driver for CastleRock integrated graphics core in the + VIA VT8623 [Apollo CLE266] chipset. + +config FB_TRIDENT + tristate "Trident/CyberXXX/CyberBlade support" + depends on FB && PCI && HAS_IOPORT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_DDC + select FB_IOMEM_FOPS + select FB_MODE_HELPERS + help + This is the frame buffer device driver for Trident PCI/AGP chipsets. + Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D + and Blade XP. + There are also integrated versions of these chips called CyberXXXX, + CyberImage or CyberBlade. These chips are mostly found in laptops + but also on some motherboards including early VIA EPIA motherboards. + For more information, read + + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tridentfb. + +config FB_ARK + tristate "ARK 2000PV support" + depends on FB && PCI && HAS_IOPORT + depends on FB_TILEBLITTING + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + select FB_SVGALIB + select VGASTATE + select FONT_8x16 if FRAMEBUFFER_CONSOLE + help + Driver for PCI graphics boards with ARK 2000PV chip + and ICS 5342 RAMDAC. + +config FB_PM3 + tristate "Permedia3 support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + +config FB_CARMINE + tristate "Fujitsu carmine frame buffer support" + depends on FB && PCI + select FB_IOMEM_HELPERS + help + This is the frame buffer device driver for the Fujitsu Carmine chip. + The driver provides two independent frame buffer devices. + +choice + depends on FB_CARMINE + prompt "DRAM timing" + default FB_CARMINE_DRAM_EVAL + +config FB_CARMINE_DRAM_EVAL + bool "Eval board timings" + help + Use timings which work on the eval card. + +config CARMINE_DRAM_CUSTOM + bool "Custom board timings" + help + Use custom board timings. +endchoice + +config FB_AU1100 + bool "Au1100 LCD Driver" + depends on FB = y + depends on MIPS_ALCHEMY || COMPILE_TEST + select FB_IOMEM_HELPERS + help + This is the framebuffer driver for the AMD Au1100 SOC. It can drive + various panels and CRTs by passing in kernel cmd line option + au1100fb:panel=. + +config FB_AU1200 + bool "Au1200/Au1300 LCD Driver" + depends on (FB = y) && MIPS_ALCHEMY + select FB_DMAMEM_HELPERS + help + This is the framebuffer driver for the Au1200/Au1300 SOCs. + It can drive various panels and CRTs by passing in kernel cmd line + option au1200fb:panel=. + +config FB_VT8500 + bool "VIA VT8500 framebuffer support" + depends on (FB = y) && ARM && ARCH_VT8500 + select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) + select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) + select FB_SYS_IMAGEBLIT + select FB_SYSMEM_FOPS + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + help + This is the framebuffer driver for VIA VT8500 integrated LCD + controller. + +config FB_WM8505 + bool "Wondermedia WM8xxx-series frame buffer support" + depends on (FB = y) && HAS_IOMEM && (ARCH_VT8500 || COMPILE_TEST) + select FB_IOMEM_FOPS + select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) + select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) + select FB_SYS_IMAGEBLIT + select FB_SYSMEM_FOPS + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + help + This is the framebuffer driver for WonderMedia WM8xxx-series + integrated LCD controller. This driver covers the WM8505, WM8650 + and WM8850 SoCs. + +config FB_WMT_GE_ROPS + bool "VT8500/WM8xxx accelerated raster ops support" + depends on (FB = y) && (FB_VT8500 || FB_WM8505) + help + This adds support for accelerated raster operations on the + VIA VT8500 and Wondermedia 85xx series SoCs. + +source "drivers/video/fbdev/geode/Kconfig" + +config FB_HIT + tristate "HD64461 Frame Buffer support" + depends on FB && HD64461 + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + This is the frame buffer device driver for the Hitachi HD64461 LCD + frame buffer card. + +config FB_PMAG_AA + tristate "PMAG-AA TURBOchannel framebuffer support" + depends on FB && TC + select FB_IOMEM_HELPERS + help + Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) + used mainly in the MIPS-based DECstation series. + +config FB_PMAG_BA + tristate "PMAG-BA TURBOchannel framebuffer support" + depends on FB && TC + select FB_IOMEM_HELPERS + help + Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) + used mainly in the MIPS-based DECstation series. + +config FB_PMAGB_B + tristate "PMAGB-B TURBOchannel framebuffer support" + depends on FB && TC + select FB_IOMEM_HELPERS + help + Support for the PMAGB-B TURBOchannel framebuffer card used mainly + in the MIPS-based DECstation series. The card is currently only + supported in 1280x1024x8 mode. + +config FB_MAXINE + bool "Maxine (Personal DECstation) onboard framebuffer support" + depends on (FB = y) && MACH_DECSTATION + select FB_IOMEM_HELPERS + help + Support for the onboard framebuffer (1024x768x8) in the Personal + DECstation series (Personal DECstation 5000/20, /25, /33, /50, + Codename "Maxine"). + +config FB_G364 + bool "G364 frame buffer support" + depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700) + select FB_IOMEM_HELPERS + help + The G364 driver is the framebuffer used in MIPS Magnum 4000 and + Olivetti M700-10 systems. + +config FB_68328 + bool "Motorola 68328 native frame buffer support" + depends on (FB = y) && (M68328 || M68EZ328 || M68VZ328) + select FB_IOMEM_HELPERS + help + Say Y here if you want to support the built-in frame buffer of + the Motorola 68328 CPU family. + +config FB_PXA168 + tristate "PXA168/910 LCD framebuffer support" + depends on FB && HAVE_CLK && HAS_IOMEM + depends on CPU_PXA168 || CPU_PXA910 || COMPILE_TEST + select FB_IOMEM_HELPERS + help + Frame buffer driver for the built-in LCD controller in the Marvell + MMP processor. + +config FB_PXA + tristate "PXA LCD framebuffer support" + depends on FB && ARCH_PXA + select FB_IOMEM_HELPERS + select VIDEOMODE_HELPERS if OF + select FB_MODE_HELPERS if OF + help + Frame buffer driver for the built-in LCD controller in the Intel + PXA2x0 processor. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called pxafb. If you want to compile it as a module, + say M here and read . + + If unsure, say N. + +config FB_PXA_OVERLAY + bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer" + depends on FB_PXA && (PXA27x || PXA3xx) + +config FB_PXA_SMARTPANEL + bool "PXA Smartpanel LCD support" + depends on FB_PXA + +config FB_PXA_PARAMETERS + bool "PXA LCD command line parameters" + depends on FB_PXA + help + Enable the use of kernel command line or module parameters + to configure the physical properties of the LCD panel when + using the PXA LCD driver. + + This option allows you to override the panel parameters + supplied by the platform in order to support multiple + different models of flatpanel. If you will only be using a + single model of flatpanel then you can safely leave this + option disabled. + + describes the available parameters. + +config PXA3XX_GCU + tristate "PXA3xx 2D graphics accelerator driver" + depends on FB_PXA + help + Kernelspace driver for the 2D graphics controller unit (GCU) + found on PXA3xx processors. There is a counterpart driver in the + DirectFB suite, see http://www.directfb.org/ + + If you compile this as a module, it will be called pxa3xx_gcu. + +config FB_FSL_DIU + tristate "Freescale DIU framebuffer support" + depends on FB && FSL_SOC + select FB_IOMEM_HELPERS + select FB_MODE_HELPERS + select PPC_LIB_RHEAP + help + Framebuffer driver for the Freescale SoC DIU + +config FB_SH_MOBILE_LCDC + tristate "SuperH Mobile LCDC framebuffer support" + depends on FB && HAVE_CLK && HAS_IOMEM + depends on SUPERH || COMPILE_TEST + depends on FB_DEVICE + depends on BACKLIGHT_CLASS_DEVICE + select FB_BACKLIGHT + select FB_DEFERRED_IO + select FB_DMAMEM_HELPERS + help + Frame buffer driver for the on-chip SH-Mobile LCD controller. + +config FB_S3C + tristate "Samsung S3C framebuffer support" + depends on FB && HAVE_CLK && HAS_IOMEM + depends on ARCH_S3C64XX || COMPILE_TEST + select FB_IOMEM_HELPERS + help + Frame buffer driver for the built-in FB controller in the Samsung + SoC line such as the S3C6400 and S3C6410. + + These chips all have the same basic framebuffer design with the + actual capabilities depending on the chip. The S3C6400 + and S3C6410 support 4 hardware windows. + + Currently the support is only for the S3C6400 and S3C6410 SoCs. + +config FB_S3C_DEBUG_REGWRITE + bool "Debug register writes" + depends on FB_S3C + help + Show all register writes via pr_debug() + +config FB_SM501 + tristate "Silicon Motion SM501 framebuffer support" + depends on FB && MFD_SM501 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_IOMEM_FOPS + help + Frame buffer driver for the CRT and LCD controllers in the Silicon + Motion SM501. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called sm501fb. If you want to compile it as a module, + say M here and read . + + If unsure, say N. + +config FB_SMSCUFX + tristate "SMSC UFX6000/7000 USB Framebuffer support" + depends on FB && USB + select FB_MODE_HELPERS + select FB_SYSMEM_HELPERS_DEFERRED + help + This is a kernel framebuffer driver for SMSC UFX USB devices. + Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and + mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000 + (USB 3.0) devices. + To compile as a module, choose M here: the module name is smscufx. + +config FB_UDL + tristate "Displaylink USB Framebuffer support" + depends on FB && USB + depends on FB_DEVICE + select FB_MODE_HELPERS + select FB_SYSMEM_HELPERS_DEFERRED + help + This is a kernel framebuffer driver for DisplayLink USB devices. + Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and + mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. + To compile as a module, choose M here: the module name is udlfb. + +config FB_IBM_GXT4500 + tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors" + depends on FB + select FB_IOMEM_HELPERS + help + Say Y here to enable support for the IBM GXT4000P/6000P and + GXT4500P/6500P display adaptor based on Raster Engine RC1000, + found on some IBM System P (pSeries) machines. This driver + doesn't use Geometry Engine GT1000. This driver also supports + AGP Fire GL2/3/4 cards on x86. + +config FB_PS3 + tristate "PS3 GPU framebuffer driver" + depends on FB && PS3_PS3AV + select FB_SYSMEM_HELPERS + help + Include support for the virtual frame buffer in the PS3 platform. + +config FB_PS3_DEFAULT_SIZE_M + int "PS3 default frame buffer size (in MiB)" + depends on FB_PS3 + default 9 + help + This is the default size (in MiB) of the virtual frame buffer in + the PS3. + The default value can be overridden on the kernel command line + using the "ps3fb" option (e.g. "ps3fb=9M"); + +config FB_XILINX + tristate "Xilinx frame buffer support" + depends on FB && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + select FB_IOMEM_HELPERS + help + Include support for the Xilinx ML300/ML403 reference design + framebuffer. ML300 carries a 640*480 LCD display on the board, + ML403 uses a standard DB15 VGA connector. + +config FB_GOLDFISH + tristate "Goldfish Framebuffer" + depends on FB + depends on GOLDFISH || COMPILE_TEST + select FB_IOMEM_HELPERS + help + Framebuffer driver for Goldfish Virtual Platform + +config FB_COBALT + tristate "Cobalt server LCD frame buffer support" + depends on FB && MIPS_COBALT + select FB_IOMEM_HELPERS + +config FB_SH7760 + tristate "SH7760/SH7763/SH7720/SH7721 LCDC support" + depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ + || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) + select FB_IOMEM_HELPERS + help + Support for the SH7760/SH7763/SH7720/SH7721 integrated + (D)STN/TFT LCD Controller. + Supports display resolutions up to 1024x1024 pixel, grayscale and + color operation, with depths ranging from 1 bpp to 8 bpp monochrome + and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for + panels <= 320 pixel horizontal resolution. + +config FB_VIRTUAL + tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" + depends on FB + select FB_SYSMEM_HELPERS + help + This is a `virtual' frame buffer device. It operates on a chunk of + unswappable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. + + To compile this driver as a module, choose M here: the + module will be called vfb. In order to load it, you must use + the vfb_enable=1 option. + + If unsure, say N. + +config XEN_FBDEV_FRONTEND + tristate "Xen virtual frame buffer support" + depends on FB && XEN + select FB_SYSMEM_HELPERS_DEFERRED + select XEN_XENBUS_FRONTEND + default y + help + This driver implements the front-end of the Xen virtual + frame buffer driver. It communicates with a back-end + in another domain. + +config FB_METRONOME + tristate "E-Ink Metronome/8track controller support" + depends on FB + select FB_SYSMEM_HELPERS_DEFERRED + help + This driver implements support for the E-Ink Metronome + controller. The pre-release name for this device was 8track + and could also have been called by some vendors as PVI-nnnn. + +config FB_MB862XX + tristate "Fujitsu MB862xx GDC support" + depends on FB + depends on PCI || (OF && PPC) + select FB_IOMEM_HELPERS + help + Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers. + +choice + prompt "GDC variant" + depends on FB_MB862XX + +config FB_MB862XX_PCI_GDC + bool "Carmine/Coral-P(A) GDC" + depends on PCI + help + This enables framebuffer support for Fujitsu Carmine/Coral-P(A) + PCI graphics controller devices. + +config FB_MB862XX_LIME + bool "Lime GDC" + depends on OF && PPC + depends on FB_LITTLE_ENDIAN || FB_BOTH_ENDIAN + help + Framebuffer support for Fujitsu Lime GDC on host CPU bus. + +endchoice + +config FB_MB862XX_I2C + bool "Support I2C bus on MB862XX GDC" + depends on FB_MB862XX && I2C + depends on FB_MB862XX=m || I2C=y + default y + help + Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter + driver to support accessing I2C devices on controller's I2C bus. + These are usually some video decoder chips. + +config FB_EP93XX + tristate "EP93XX frame buffer support" + depends on FB && ARCH_EP93XX + select FB_IOMEM_HELPERS + help + Framebuffer driver for the Cirrus Logic EP93XX series of processors. + This driver is also available as a module. The module will be called + ep93xx-fb. + +config FB_PRE_INIT_FB + bool "Don't reinitialize, use bootloader's GDC/Display configuration" + depends on FB && FB_MB862XX_LIME + help + Select this option if display contents should be inherited as set by + the bootloader. + +config FB_BROADSHEET + tristate "E-Ink Broadsheet/Epson S1D13521 controller support" + depends on FB && (ARCH_PXA || COMPILE_TEST) + select FB_SYSMEM_HELPERS_DEFERRED + help + This driver implements support for the E-Ink Broadsheet + controller. The release name for this device was Epson S1D13521 + and could also have been called by other names when coupled with + a bridge adapter. + +config FB_SIMPLE + tristate "Simple framebuffer support" + depends on FB + depends on !DRM_SIMPLEDRM + select APERTURE_HELPERS + select FB_IOMEM_HELPERS + help + Say Y if you want support for a simple frame-buffer. + + This driver assumes that the display hardware has been initialized + before the kernel boots, and the kernel will simply render to the + pre-allocated frame buffer surface. + + Configuration re: surface address, size, and format must be provided + through device tree, or plain old platform data. + +config FB_SSD1307 + tristate "Solomon SSD1307 framebuffer support" + depends on FB && I2C + depends on GPIOLIB || COMPILE_TEST + depends on BACKLIGHT_CLASS_DEVICE + select FB_BACKLIGHT + select FB_SYSMEM_HELPERS_DEFERRED + help + This driver implements support for the Solomon SSD1307 + OLED controller over I2C. + +config FB_SM712 + tristate "Silicon Motion SM712 framebuffer support" + depends on FB && PCI && HAS_IOPORT + select FB_IOMEM_HELPERS + help + Frame buffer driver for the Silicon Motion SM710, SM712, SM721 + and SM722 chips. + + This driver is also available as a module. The module will be + called sm712fb. If you want to compile it as a module, say M + here and read . + +source "drivers/video/fbdev/omap/Kconfig" +source "drivers/video/fbdev/omap2/Kconfig" +source "drivers/video/fbdev/mmp/Kconfig" + +source "drivers/video/fbdev/core/Kconfig" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile new file mode 100644 index 000000000..0b17c8781 --- /dev/null +++ b/drivers/video/fbdev/Makefile @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for the Linux video drivers. +# 5 Aug 1999, James Simmons, +# Rewritten to use lists instead of if-statements. + +# Each configuration option enables a list of files. + +obj-y += core/ + +obj-$(CONFIG_FB_MACMODES) += macmodes.o +obj-$(CONFIG_FB_SBUS) += sbuslib.o +obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o + +# Hardware specific drivers go first +obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o +obj-$(CONFIG_FB_ARC) += arcfb.o +obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o +obj-$(CONFIG_FB_GRVGA) += grvga.o +obj-$(CONFIG_FB_PM2) += pm2fb.o +obj-$(CONFIG_FB_PM3) += pm3fb.o + +obj-$(CONFIG_FB_I740) += i740fb.o +obj-$(CONFIG_FB_MATROX) += matrox/ +obj-$(CONFIG_FB_RIVA) += riva/ +obj-$(CONFIG_FB_NVIDIA) += nvidia/ +obj-$(CONFIG_FB_ATY) += aty/ macmodes.o +obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o +obj-$(CONFIG_FB_RADEON) += aty/ +obj-$(CONFIG_FB_SIS) += sis/ +obj-$(CONFIG_FB_VIA) += via/ +obj-$(CONFIG_FB_KYRO) += kyro/ +obj-$(CONFIG_FB_SAVAGE) += savage/ +obj-$(CONFIG_FB_GEODE) += geode/ +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o +obj-$(CONFIG_FB_3DFX) += tdfxfb.o +obj-$(CONFIG_FB_CONTROL) += controlfb.o +obj-$(CONFIG_FB_PLATINUM) += platinumfb.o +obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o +obj-$(CONFIG_FB_CT65550) += chipsfb.o +obj-$(CONFIG_FB_IMSTT) += imsttfb.o +obj-$(CONFIG_FB_FM2) += fm2fb.o +obj-$(CONFIG_FB_VT8623) += vt8623fb.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o +obj-$(CONFIG_FB_S3) += s3fb.o +obj-$(CONFIG_FB_ARK) += arkfb.o +obj-$(CONFIG_FB_STI) += stifb.o +obj-$(CONFIG_FB_FFB) += ffb.o +obj-$(CONFIG_FB_CG6) += cg6.o +obj-$(CONFIG_FB_CG3) += cg3.o +obj-$(CONFIG_FB_BW2) += bw2.o +obj-$(CONFIG_FB_CG14) += cg14.o +obj-$(CONFIG_FB_P9100) += p9100.o +obj-$(CONFIG_FB_TCX) += tcx.o +obj-$(CONFIG_FB_LEO) += leo.o +obj-$(CONFIG_FB_ACORN) += acornfb.o +obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ + atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o +obj-$(CONFIG_FB_MAC) += macfb.o +obj-$(CONFIG_FB_HECUBA) += hecubafb.o +obj-$(CONFIG_FB_N411) += n411.o +obj-$(CONFIG_FB_XVR500) += sunxvr500.o +obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o +obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o +obj-$(CONFIG_FB_Q40) += q40fb.o +obj-$(CONFIG_FB_TGA) += tgafb.o +obj-$(CONFIG_FB_HP300) += hpfb.o +obj-$(CONFIG_FB_G364) += g364fb.o +obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o +obj-$(CONFIG_FB_SA1100) += sa1100fb.o +obj-$(CONFIG_FB_HIT) += hitfb.o +obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o +obj-$(CONFIG_FB_PVR2) += pvr2fb.o +obj-$(CONFIG_FB_VOODOO1) += sstfb.o +obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o +obj-$(CONFIG_FB_68328) += 68328fb.o +obj-$(CONFIG_FB_GBE) += gbefb.o +obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o +obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o +obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_PXA168) += pxa168fb.o +obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o +obj-$(CONFIG_MMP_DISP) += mmp/ +obj-$(CONFIG_FB_AU1100) += au1100fb.o +obj-$(CONFIG_FB_AU1200) += au1200fb.o +obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o +obj-$(CONFIG_FB_WM8505) += wm8505fb.o +obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o +obj-$(CONFIG_FB_METRONOME) += metronomefb.o +obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o +obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o +obj-$(CONFIG_FB_SH7760) += sh7760fb.o +obj-$(CONFIG_FB_IMX) += imxfb.o +obj-$(CONFIG_FB_S3C) += s3c-fb.o +obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o +obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o +obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o +obj-$(CONFIG_FB_PS3) += ps3fb.o +obj-$(CONFIG_FB_SM501) += sm501fb.o +obj-$(CONFIG_FB_UDL) += udlfb.o +obj-$(CONFIG_FB_SMSCUFX) += smscufx.o +obj-$(CONFIG_FB_XILINX) += xilinxfb.o +obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o +obj-y += omap/ +obj-y += omap2/ +obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o +obj-$(CONFIG_FB_CARMINE) += carminefb.o +obj-$(CONFIG_FB_MB862XX) += mb862xx/ +obj-$(CONFIG_FB_OPENCORES) += ocfb.o +obj-$(CONFIG_FB_SM712) += sm712fb.o + +# Platform or fallback drivers go here +obj-$(CONFIG_FB_UVESA) += uvesafb.o +obj-$(CONFIG_FB_VESA) += vesafb.o +obj-$(CONFIG_FB_EFI) += efifb.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o +obj-$(CONFIG_FB_OF) += offb.o +obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o +obj-$(CONFIG_FB_SIMPLE) += simplefb.o + +# the test framebuffer is last +obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/fbdev/acornfb.c b/drivers/video/fbdev/acornfb.c new file mode 100644 index 000000000..f0600f6ca --- /dev/null +++ b/drivers/video/fbdev/acornfb.c @@ -0,0 +1,1102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/video/acornfb.c + * + * Copyright (C) 1998-2001 Russell King + * + * Frame buffer code for Acorn platforms + * + * NOTE: Most of the modes with X!=640 will disappear shortly. + * NOTE: Startup setting of HS & VS polarity not supported. + * (do we need to support it if we're coming up in 640x480?) + * + * FIXME: (things broken by the "new improved" FBCON API) + * - Blanking 8bpp displays with VIDC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "acornfb.h" + +/* + * Default resolution. + * NOTE that it has to be supported in the table towards + * the end of this file. + */ +#define DEFAULT_XRES 640 +#define DEFAULT_YRES 480 +#define DEFAULT_BPP 4 + +/* + * define this to debug the video mode selection + */ +#undef DEBUG_MODE_SELECTION + +/* + * Translation from RISC OS monitor types to actual + * HSYNC and VSYNC frequency ranges. These are + * probably not right, but they're the best info I + * have. Allow 1% either way on the nominal for TVs. + */ +#define NR_MONTYPES 6 +static struct fb_monspecs monspecs[NR_MONTYPES] = { + { /* TV */ + .hfmin = 15469, + .hfmax = 15781, + .vfmin = 49, + .vfmax = 51, + }, { /* Multi Freq */ + .hfmin = 0, + .hfmax = 99999, + .vfmin = 0, + .vfmax = 199, + }, { /* Hi-res mono */ + .hfmin = 58608, + .hfmax = 58608, + .vfmin = 64, + .vfmax = 64, + }, { /* VGA */ + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + }, { /* SVGA */ + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 56, + .vfmax = 75, + }, { + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + } +}; + +static struct fb_info fb_info; +static struct acornfb_par current_par; +static struct vidc_timing current_vidc; + +extern unsigned int vram_size; /* set by setup.c */ + +#ifdef HAS_VIDC20 +#include + +#define MAX_SIZE (2*1024*1024) + +/* VIDC20 has a different set of rules from the VIDC: + * hcr : must be multiple of 4 + * hswr : must be even + * hdsr : must be even + * hder : must be even + * vcr : >= 2, (interlace, must be odd) + * vswr : >= 1 + * vdsr : >= 1 + * vder : >= vdsr + */ +static void acornfb_set_timing(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct vidc_timing vidc; + u_int vcr, fsize; + u_int ext_ctl, dat_ctl; + u_int words_per_line; + + memset(&vidc, 0, sizeof(vidc)); + + vidc.h_sync_width = var->hsync_len - 8; + vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12; + vidc.h_display_start = vidc.h_border_start + 12 - 18; + vidc.h_display_end = vidc.h_display_start + var->xres; + vidc.h_border_end = vidc.h_display_end + 18 - 12; + vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8; + vidc.h_interlace = vidc.h_cycle / 2; + vidc.v_sync_width = var->vsync_len - 1; + vidc.v_border_start = vidc.v_sync_width + var->upper_margin; + vidc.v_display_start = vidc.v_border_start; + vidc.v_display_end = vidc.v_display_start + var->yres; + vidc.v_border_end = vidc.v_display_end; + vidc.control = acornfb_default_control(); + + vcr = var->vsync_len + var->upper_margin + var->yres + + var->lower_margin; + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vidc.v_cycle = (vcr - 3) / 2; + vidc.control |= VIDC20_CTRL_INT; + } else + vidc.v_cycle = vcr - 2; + + switch (var->bits_per_pixel) { + case 1: vidc.control |= VIDC20_CTRL_1BPP; break; + case 2: vidc.control |= VIDC20_CTRL_2BPP; break; + case 4: vidc.control |= VIDC20_CTRL_4BPP; break; + default: + case 8: vidc.control |= VIDC20_CTRL_8BPP; break; + case 16: vidc.control |= VIDC20_CTRL_16BPP; break; + case 32: vidc.control |= VIDC20_CTRL_32BPP; break; + } + + acornfb_vidc20_find_rates(&vidc, var); + fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1; + + if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { + current_vidc = vidc; + + vidc_writel(VIDC20_CTRL | vidc.control); + vidc_writel(0xd0000000 | vidc.pll_ctl); + vidc_writel(0x80000000 | vidc.h_cycle); + vidc_writel(0x81000000 | vidc.h_sync_width); + vidc_writel(0x82000000 | vidc.h_border_start); + vidc_writel(0x83000000 | vidc.h_display_start); + vidc_writel(0x84000000 | vidc.h_display_end); + vidc_writel(0x85000000 | vidc.h_border_end); + vidc_writel(0x86000000); + vidc_writel(0x87000000 | vidc.h_interlace); + vidc_writel(0x90000000 | vidc.v_cycle); + vidc_writel(0x91000000 | vidc.v_sync_width); + vidc_writel(0x92000000 | vidc.v_border_start); + vidc_writel(0x93000000 | vidc.v_display_start); + vidc_writel(0x94000000 | vidc.v_display_end); + vidc_writel(0x95000000 | vidc.v_border_end); + vidc_writel(0x96000000); + vidc_writel(0x97000000); + } + + iomd_writel(fsize, IOMD_FSIZE); + + ext_ctl = acornfb_default_econtrol(); + + if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ + ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC; + else { + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + ext_ctl |= VIDC20_ECTL_HS_HSYNC; + else + ext_ctl |= VIDC20_ECTL_HS_NHSYNC; + + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + ext_ctl |= VIDC20_ECTL_VS_VSYNC; + else + ext_ctl |= VIDC20_ECTL_VS_NVSYNC; + } + + vidc_writel(VIDC20_ECTL | ext_ctl); + + words_per_line = var->xres * var->bits_per_pixel / 32; + + if (current_par.using_vram && info->fix.smem_len == 2048*1024) + words_per_line /= 2; + + /* RiscPC doesn't use the VIDC's VRAM control. */ + dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line; + + /* The data bus width is dependent on both the type + * and amount of video memory. + * DRAM 32bit low + * 1MB VRAM 32bit + * 2MB VRAM 64bit + */ + if (current_par.using_vram && current_par.vram_half_sam == 2048) + dat_ctl |= VIDC20_DCTL_BUS_D63_0; + else + dat_ctl |= VIDC20_DCTL_BUS_D31_0; + + vidc_writel(VIDC20_DCTL | dat_ctl); + +#ifdef DEBUG_MODE_SELECTION + printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, + var->yres, var->bits_per_pixel); + printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); + printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); + printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); + printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); + printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); + printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); + printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); + printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); + printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); + printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); + printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); + printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); + printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); + printk(KERN_DEBUG " Ext Ctrl (C) : 0x%08X\n", ext_ctl); + printk(KERN_DEBUG " PLL Ctrl (D) : 0x%08X\n", vidc.pll_ctl); + printk(KERN_DEBUG " Ctrl (E) : 0x%08X\n", vidc.control); + printk(KERN_DEBUG " Data Ctrl (F) : 0x%08X\n", dat_ctl); + printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize); +#endif +} + +/* + * We have to take note of the VIDC20's 16-bit palette here. + * The VIDC20 looks up a 16 bit pixel as follows: + * + * bits 111111 + * 5432109876543210 + * red ++++++++ (8 bits, 7 to 0) + * green ++++++++ (8 bits, 11 to 4) + * blue ++++++++ (8 bits, 15 to 8) + * + * We use a pixel which looks like: + * + * bits 111111 + * 5432109876543210 + * red +++++ (5 bits, 4 to 0) + * green +++++ (5 bits, 9 to 5) + * blue +++++ (5 bits, 14 to 10) + */ +static int +acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int trans, struct fb_info *info) +{ + union palette pal; + + if (regno >= current_par.palette_size) + return 1; + + if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + u32 pseudo_val; + + pseudo_val = regno << info->var.red.offset; + pseudo_val |= regno << info->var.green.offset; + pseudo_val |= regno << info->var.blue.offset; + + ((u32 *)info->pseudo_palette)[regno] = pseudo_val; + } + + pal.p = 0; + pal.vidc20.red = red >> 8; + pal.vidc20.green = green >> 8; + pal.vidc20.blue = blue >> 8; + + current_par.palette[regno] = pal; + + if (info->var.bits_per_pixel == 16) { + int i; + + pal.p = 0; + vidc_writel(0x10000000); + for (i = 0; i < 256; i += 1) { + pal.vidc20.red = current_par.palette[i & 31].vidc20.red; + pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; + pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; + vidc_writel(pal.p); + /* Palette register pointer auto-increments */ + } + } else { + vidc_writel(0x10000000 | regno); + vidc_writel(pal.p); + } + + return 0; +} +#endif + +/* + * Before selecting the timing parameters, adjust + * the resolution to fit the rules. + */ +static int +acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht) +{ + u_int font_line_len, sam_size, min_size, size, nr_y; + + /* xres must be even */ + var->xres = (var->xres + 1) & ~1; + + /* + * We don't allow xres_virtual to differ from xres + */ + var->xres_virtual = var->xres; + var->xoffset = 0; + + if (current_par.using_vram) + sam_size = current_par.vram_half_sam * 2; + else + sam_size = 16; + + /* + * Now, find a value for yres_virtual which allows + * us to do ywrap scrolling. The value of + * yres_virtual must be such that the end of the + * displayable frame buffer must be aligned with + * the start of a font line. + */ + font_line_len = var->xres * var->bits_per_pixel * fontht / 8; + min_size = var->xres * var->yres * var->bits_per_pixel / 8; + + /* + * If minimum screen size is greater than that we have + * available, reject it. + */ + if (min_size > info->fix.smem_len) + return -EINVAL; + + /* Find int 'y', such that y * fll == s * sam < maxsize + * y = s * sam / fll; s = maxsize / sam + */ + for (size = info->fix.smem_len; + nr_y = size / font_line_len, min_size <= size; + size -= sam_size) { + if (nr_y * font_line_len == size) + break; + } + nr_y *= fontht; + + if (var->accel_flags & FB_ACCELF_TEXT) { + if (min_size > size) { + /* + * failed, use ypan + */ + size = info->fix.smem_len; + var->yres_virtual = size / (font_line_len / fontht); + } else + var->yres_virtual = nr_y; + } else if (var->yres_virtual > nr_y) + var->yres_virtual = nr_y; + + current_par.screen_end = info->fix.smem_start + size; + + /* + * Fix yres & yoffset if needed. + */ + if (var->yres > var->yres_virtual) + var->yres = var->yres_virtual; + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset > var->yres_virtual) + var->yoffset = var->yres_virtual; + } else { + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + } + + /* hsync_len must be even */ + var->hsync_len = (var->hsync_len + 1) & ~1; + +#if defined(HAS_VIDC20) + /* left_margin must be even */ + if (var->left_margin & 1) { + var->left_margin += 1; + var->right_margin -= 1; + } + + /* right_margin must be even */ + if (var->right_margin & 1) + var->right_margin += 1; +#endif + + if (var->vsync_len < 1) + var->vsync_len = 1; + + return 0; +} + +static int +acornfb_validate_timing(struct fb_var_screeninfo *var, + struct fb_monspecs *monspecs) +{ + unsigned long hs, vs; + + /* + * hs(Hz) = 10^12 / (pixclock * xtotal) + * vs(Hz) = hs(Hz) / ytotal + * + * No need to do long long divisions or anything + * like that if you factor it correctly + */ + hs = 1953125000 / var->pixclock; + hs = hs * 512 / + (var->xres + var->left_margin + var->right_margin + var->hsync_len); + vs = hs / + (var->yres + var->upper_margin + var->lower_margin + var->vsync_len); + + return (vs >= monspecs->vfmin && vs <= monspecs->vfmax && + hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL; +} + +static inline void +acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) +{ + u_int off = var->yoffset * info->fix.line_length; + +#if defined(HAS_MEMC) + memc_write(VDMA_INIT, off >> 2); +#elif defined(HAS_IOMD) + iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); +#endif +} + +static int +acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u_int fontht; + int err; + + /* + * FIXME: Find the font height + */ + fontht = 8; + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + + switch (var->bits_per_pixel) { + case 1: case 2: case 4: case 8: + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + var->transp.offset = 0; + var->transp.length = 0; + break; + +#ifdef HAS_VIDC20 + case 16: + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + + case 32: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 4; + break; +#endif + default: + return -EINVAL; + } + + /* + * Check to see if the pixel rate is valid. + */ + if (!acornfb_valid_pixrate(var)) + return -EINVAL; + + /* + * Validate and adjust the resolution to + * match the video generator hardware. + */ + err = acornfb_adjust_timing(info, var, fontht); + if (err) + return err; + + /* + * Validate the timing against the + * monitor hardware. + */ + return acornfb_validate_timing(var, &info->monspecs); +} + +static int acornfb_set_par(struct fb_info *info) +{ + switch (info->var.bits_per_pixel) { + case 1: + current_par.palette_size = 2; + info->fix.visual = FB_VISUAL_MONO10; + break; + case 2: + current_par.palette_size = 4; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 4: + current_par.palette_size = 16; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 8: + current_par.palette_size = VIDC_PALETTE_SIZE; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; +#ifdef HAS_VIDC20 + case 16: + current_par.palette_size = 32; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + break; + case 32: + current_par.palette_size = VIDC_PALETTE_SIZE; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + break; +#endif + default: + BUG(); + } + + info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8; + +#if defined(HAS_MEMC) + { + unsigned long size = info->fix.smem_len - VDMA_XFERSIZE; + + memc_write(VDMA_START, 0); + memc_write(VDMA_END, size >> 2); + } +#elif defined(HAS_IOMD) + { + unsigned long start, size; + u_int control; + + start = info->fix.smem_start; + size = current_par.screen_end; + + if (current_par.using_vram) { + size -= current_par.vram_half_sam; + control = DMA_CR_E | (current_par.vram_half_sam / 256); + } else { + size -= 16; + control = DMA_CR_E | DMA_CR_D | 16; + } + + iomd_writel(start, IOMD_VIDSTART); + iomd_writel(size, IOMD_VIDEND); + iomd_writel(control, IOMD_VIDCR); + } +#endif + + acornfb_update_dma(info, &info->var); + acornfb_set_timing(info); + + return 0; +} + +static int +acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u_int y_bottom = var->yoffset; + + if (!(var->vmode & FB_VMODE_YWRAP)) + y_bottom += info->var.yres; + + if (y_bottom > info->var.yres_virtual) + return -EINVAL; + + acornfb_update_dma(info, var); + + return 0; +} + +static const struct fb_ops acornfb_ops = { + .owner = THIS_MODULE, + FB_DEFAULT_IOMEM_OPS, + .fb_check_var = acornfb_check_var, + .fb_set_par = acornfb_set_par, + .fb_setcolreg = acornfb_setcolreg, + .fb_pan_display = acornfb_pan_display, +}; + +/* + * Everything after here is initialisation!!! + */ +static struct fb_videomode modedb[] = { + { /* 320x256 @ 50Hz */ + NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, + FB_SYNC_COMP_HIGH_ACT, + FB_VMODE_NONINTERLACED + }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */ + NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */ + NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */ + NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */ + NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */ + NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2, + 0, + FB_VMODE_NONINTERLACED + }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */ + NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3, + 0, + FB_VMODE_NONINTERLACED + }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */ + NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, + 0, + FB_VMODE_NONINTERLACED + }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */ + NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3, + 0, + FB_VMODE_NONINTERLACED + } +}; + +static struct fb_videomode acornfb_default_mode = { + .name = NULL, + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 56, + .right_margin = 16, + .upper_margin = 34, + .lower_margin = 9, + .hsync_len = 88, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +static void acornfb_init_fbinfo(void) +{ + static int first = 1; + + if (!first) + return; + first = 0; + + fb_info.fbops = &acornfb_ops; + fb_info.flags = FBINFO_HWACCEL_YPAN; + fb_info.pseudo_palette = current_par.pseudo_palette; + + strcpy(fb_info.fix.id, "Acorn"); + fb_info.fix.type = FB_TYPE_PACKED_PIXELS; + fb_info.fix.type_aux = 0; + fb_info.fix.xpanstep = 0; + fb_info.fix.ypanstep = 1; + fb_info.fix.ywrapstep = 1; + fb_info.fix.line_length = 0; + fb_info.fix.accel = FB_ACCEL_NONE; + + /* + * setup initial parameters + */ + memset(&fb_info.var, 0, sizeof(fb_info.var)); + +#if defined(HAS_VIDC20) + fb_info.var.red.length = 8; + fb_info.var.transp.length = 4; +#endif + fb_info.var.green = fb_info.var.red; + fb_info.var.blue = fb_info.var.red; + fb_info.var.nonstd = 0; + fb_info.var.activate = FB_ACTIVATE_NOW; + fb_info.var.height = -1; + fb_info.var.width = -1; + fb_info.var.vmode = FB_VMODE_NONINTERLACED; + fb_info.var.accel_flags = FB_ACCELF_TEXT; + + current_par.dram_size = 0; + current_par.montype = -1; + current_par.dpms = 0; +} + +/* + * setup acornfb options: + * + * mon:hmin-hmax:vmin-vmax:dpms:width:height + * Set monitor parameters: + * hmin = horizontal minimum frequency (Hz) + * hmax = horizontal maximum frequency (Hz) (optional) + * vmin = vertical minimum frequency (Hz) + * vmax = vertical maximum frequency (Hz) (optional) + * dpms = DPMS supported? (optional) + * width = width of picture in mm. (optional) + * height = height of picture in mm. (optional) + * + * montype:type + * Set RISC-OS style monitor type: + * 0 (or tv) - TV frequency + * 1 (or multi) - Multi frequency + * 2 (or hires) - Hi-res monochrome + * 3 (or vga) - VGA + * 4 (or svga) - SVGA + * auto, or option missing + * - try hardware detect + * + * dram:size + * Set the amount of DRAM to use for the frame buffer + * (even if you have VRAM). + * size can optionally be followed by 'M' or 'K' for + * MB or KB respectively. + */ +static void acornfb_parse_mon(char *opt) +{ + char *p = opt; + + current_par.montype = -2; + + fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0); + if (*p == '-') + fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0); + else + fb_info.monspecs.hfmax = fb_info.monspecs.hfmin; + + if (*p != ':') + goto bad; + + fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0); + if (*p == '-') + fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0); + else + fb_info.monspecs.vfmax = fb_info.monspecs.vfmin; + + if (*p != ':') + goto check_values; + + fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0); + + if (*p != ':') + goto check_values; + + fb_info.var.width = simple_strtoul(p + 1, &p, 0); + + if (*p != ':') + goto check_values; + + fb_info.var.height = simple_strtoul(p + 1, NULL, 0); + +check_values: + if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin || + fb_info.monspecs.vfmax < fb_info.monspecs.vfmin) + goto bad; + return; + +bad: + printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt); + current_par.montype = -1; +} + +static void acornfb_parse_montype(char *opt) +{ + current_par.montype = -2; + + if (strncmp(opt, "tv", 2) == 0) { + opt += 2; + current_par.montype = 0; + } else if (strncmp(opt, "multi", 5) == 0) { + opt += 5; + current_par.montype = 1; + } else if (strncmp(opt, "hires", 5) == 0) { + opt += 5; + current_par.montype = 2; + } else if (strncmp(opt, "vga", 3) == 0) { + opt += 3; + current_par.montype = 3; + } else if (strncmp(opt, "svga", 4) == 0) { + opt += 4; + current_par.montype = 4; + } else if (strncmp(opt, "auto", 4) == 0) { + opt += 4; + current_par.montype = -1; + } else if (isdigit(*opt)) + current_par.montype = simple_strtoul(opt, &opt, 0); + + if (current_par.montype == -2 || + current_par.montype > NR_MONTYPES) { + printk(KERN_ERR "acornfb: unknown monitor type: %s\n", + opt); + current_par.montype = -1; + } else + if (opt && *opt) { + if (strcmp(opt, ",dpms") == 0) + current_par.dpms = 1; + else + printk(KERN_ERR + "acornfb: unknown monitor option: %s\n", + opt); + } +} + +static void acornfb_parse_dram(char *opt) +{ + unsigned int size; + + size = simple_strtoul(opt, &opt, 0); + + if (opt) { + switch (*opt) { + case 'M': + case 'm': + size *= 1024; + fallthrough; + case 'K': + case 'k': + size *= 1024; + default: + break; + } + } + + current_par.dram_size = size; +} + +static struct options { + char *name; + void (*parse)(char *opt); +} opt_table[] = { + { "mon", acornfb_parse_mon }, + { "montype", acornfb_parse_montype }, + { "dram", acornfb_parse_dram }, + { NULL, NULL } +}; + +static int acornfb_setup(char *options) +{ + struct options *optp; + char *opt; + + if (!options || !*options) + return 0; + + acornfb_init_fbinfo(); + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + for (optp = opt_table; optp->name; optp++) { + int optlen; + + optlen = strlen(optp->name); + + if (strncmp(opt, optp->name, optlen) == 0 && + opt[optlen] == ':') { + optp->parse(opt + optlen + 1); + break; + } + } + + if (!optp->name) + printk(KERN_ERR "acornfb: unknown parameter: %s\n", + opt); + } + return 0; +} + +/* + * Detect type of monitor connected + * For now, we just assume SVGA + */ +static int acornfb_detect_monitortype(void) +{ + return 4; +} + +static int acornfb_probe(struct platform_device *dev) +{ + unsigned long size; + u_int h_sync, v_sync; + int rc, i; + char *option = NULL; + + if (fb_get_options("acornfb", &option)) + return -ENODEV; + acornfb_setup(option); + + acornfb_init_fbinfo(); + + current_par.dev = &dev->dev; + + if (current_par.montype == -1) + current_par.montype = acornfb_detect_monitortype(); + + if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) + current_par.montype = 4; + + if (current_par.montype >= 0) { + fb_info.monspecs = monspecs[current_par.montype]; + fb_info.monspecs.dpms = current_par.dpms; + } + + /* + * Try to select a suitable default mode + */ + for (i = 0; i < ARRAY_SIZE(modedb); i++) { + unsigned long hs; + + hs = modedb[i].refresh * + (modedb[i].yres + modedb[i].upper_margin + + modedb[i].lower_margin + modedb[i].vsync_len); + if (modedb[i].xres == DEFAULT_XRES && + modedb[i].yres == DEFAULT_YRES && + modedb[i].refresh >= fb_info.monspecs.vfmin && + modedb[i].refresh <= fb_info.monspecs.vfmax && + hs >= fb_info.monspecs.hfmin && + hs <= fb_info.monspecs.hfmax) { + acornfb_default_mode = modedb[i]; + break; + } + } + + fb_info.screen_base = (char *)SCREEN_BASE; + fb_info.fix.smem_start = SCREEN_START; + current_par.using_vram = 0; + + /* + * If vram_size is set, we are using VRAM in + * a Risc PC. However, if the user has specified + * an amount of DRAM then use that instead. + */ + if (vram_size && !current_par.dram_size) { + size = vram_size; + current_par.vram_half_sam = vram_size / 1024; + current_par.using_vram = 1; + } else if (current_par.dram_size) + size = current_par.dram_size; + else + size = MAX_SIZE; + + /* + * Limit maximum screen size. + */ + if (size > MAX_SIZE) + size = MAX_SIZE; + + size = PAGE_ALIGN(size); + +#if defined(HAS_VIDC20) + if (!current_par.using_vram) { + dma_addr_t handle; + void *base; + + /* + * RiscPC needs to allocate the DRAM memory + * for the framebuffer if we are not using + * VRAM. + */ + base = dma_alloc_wc(current_par.dev, size, &handle, + GFP_KERNEL); + if (base == NULL) { + printk(KERN_ERR "acornfb: unable to allocate screen memory\n"); + return -ENOMEM; + } + + fb_info.screen_base = base; + fb_info.fix.smem_start = handle; + } +#endif + fb_info.fix.smem_len = size; + current_par.palette_size = VIDC_PALETTE_SIZE; + + /* + * Lookup the timing for this resolution. If we can't + * find it, then we can't restore it if we change + * the resolution, so we disable this feature. + */ + do { + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, + ARRAY_SIZE(modedb), + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, + ARRAY_SIZE(modedb), + &acornfb_default_mode, DEFAULT_BPP); + if (rc) + break; + + rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + } while (0); + + /* + * If we didn't find an exact match, try the + * generic database. + */ + if (rc == 0) { + printk("Acornfb: no valid mode found\n"); + return -EINVAL; + } + + h_sync = 1953125000 / fb_info.var.pixclock; + h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin + + fb_info.var.right_margin + fb_info.var.hsync_len); + v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin + + fb_info.var.lower_margin + fb_info.var.vsync_len); + + printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n", + fb_info.fix.smem_len / 1024, + current_par.using_vram ? 'V' : 'D', + VIDC_NAME, fb_info.var.xres, fb_info.var.yres, + h_sync / 1000, h_sync % 1000, v_sync); + + printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n", + fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000, + fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000, + fb_info.monspecs.vfmin, fb_info.monspecs.vfmax, + fb_info.monspecs.dpms ? ", DPMS" : ""); + + if (fb_set_var(&fb_info, &fb_info.var)) + printk(KERN_ERR "Acornfb: unable to set display parameters\n"); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + return 0; +} + +static struct platform_driver acornfb_driver = { + .probe = acornfb_probe, + .driver = { + .name = "acornfb", + }, +}; + +static int __init acornfb_init(void) +{ + return platform_driver_register(&acornfb_driver); +} + +module_init(acornfb_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/acornfb.h b/drivers/video/fbdev/acornfb.h new file mode 100644 index 000000000..f8df4ecb4 --- /dev/null +++ b/drivers/video/fbdev/acornfb.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/drivers/video/acornfb.h + * + * Copyright (C) 1998,1999 Russell King + * + * Frame buffer code for Acorn platforms + */ +#if defined(HAS_VIDC20) +#include +#define VIDC_PALETTE_SIZE 256 +#define VIDC_NAME "VIDC20" +#endif + +#define EXTEND8(x) ((x)|(x)<<8) +#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12) + +struct vidc20_palette { + u_int red:8; + u_int green:8; + u_int blue:8; + u_int ext:4; + u_int unused:4; +}; + +struct vidc_palette { + u_int red:4; + u_int green:4; + u_int blue:4; + u_int trans:1; + u_int sbz1:13; + u_int reg:4; + u_int sbz2:2; +}; + +union palette { + struct vidc20_palette vidc20; + struct vidc_palette vidc; + u_int p; +}; + +struct acornfb_par { + struct device *dev; + unsigned long screen_end; + unsigned int dram_size; + unsigned int vram_half_sam; + unsigned int palette_size; + signed int montype; + unsigned int using_vram : 1; + unsigned int dpms : 1; + + union palette palette[VIDC_PALETTE_SIZE]; + + u32 pseudo_palette[16]; +}; + +struct vidc_timing { + u_int h_cycle; + u_int h_sync_width; + u_int h_border_start; + u_int h_display_start; + u_int h_display_end; + u_int h_border_end; + u_int h_interlace; + + u_int v_cycle; + u_int v_sync_width; + u_int v_border_start; + u_int v_display_start; + u_int v_display_end; + u_int v_border_end; + + u_int control; + + /* VIDC20 only */ + u_int pll_ctl; +}; + +struct modey_params { + u_int y_res; + u_int u_margin; + u_int b_margin; + u_int vsync_len; + u_int vf; +}; + +struct modex_params { + u_int x_res; + u_int l_margin; + u_int r_margin; + u_int hsync_len; + u_int clock; + u_int hf; + const struct modey_params *modey; +}; + +#ifdef HAS_VIDC20 +/* + * VIDC20 registers + */ +#define VIDC20_CTRL 0xe0000000 +#define VIDC20_CTRL_PIX_VCLK (0 << 0) +#define VIDC20_CTRL_PIX_HCLK (1 << 0) +#define VIDC20_CTRL_PIX_RCLK (2 << 0) +#define VIDC20_CTRL_PIX_CK (0 << 2) +#define VIDC20_CTRL_PIX_CK2 (1 << 2) +#define VIDC20_CTRL_PIX_CK3 (2 << 2) +#define VIDC20_CTRL_PIX_CK4 (3 << 2) +#define VIDC20_CTRL_PIX_CK5 (4 << 2) +#define VIDC20_CTRL_PIX_CK6 (5 << 2) +#define VIDC20_CTRL_PIX_CK7 (6 << 2) +#define VIDC20_CTRL_PIX_CK8 (7 << 2) +#define VIDC20_CTRL_1BPP (0 << 5) +#define VIDC20_CTRL_2BPP (1 << 5) +#define VIDC20_CTRL_4BPP (2 << 5) +#define VIDC20_CTRL_8BPP (3 << 5) +#define VIDC20_CTRL_16BPP (4 << 5) +#define VIDC20_CTRL_32BPP (6 << 5) +#define VIDC20_CTRL_FIFO_NS (0 << 8) +#define VIDC20_CTRL_FIFO_4 (1 << 8) +#define VIDC20_CTRL_FIFO_8 (2 << 8) +#define VIDC20_CTRL_FIFO_12 (3 << 8) +#define VIDC20_CTRL_FIFO_16 (4 << 8) +#define VIDC20_CTRL_FIFO_20 (5 << 8) +#define VIDC20_CTRL_FIFO_24 (6 << 8) +#define VIDC20_CTRL_FIFO_28 (7 << 8) +#define VIDC20_CTRL_INT (1 << 12) +#define VIDC20_CTRL_DUP (1 << 13) +#define VIDC20_CTRL_PDOWN (1 << 14) + +#define VIDC20_ECTL 0xc0000000 +#define VIDC20_ECTL_REG(x) ((x) & 0xf3) +#define VIDC20_ECTL_ECK (1 << 2) +#define VIDC20_ECTL_REDPED (1 << 8) +#define VIDC20_ECTL_GREENPED (1 << 9) +#define VIDC20_ECTL_BLUEPED (1 << 10) +#define VIDC20_ECTL_DAC (1 << 12) +#define VIDC20_ECTL_LCDGS (1 << 13) +#define VIDC20_ECTL_HRM (1 << 14) + +#define VIDC20_ECTL_HS_MASK (3 << 16) +#define VIDC20_ECTL_HS_HSYNC (0 << 16) +#define VIDC20_ECTL_HS_NHSYNC (1 << 16) +#define VIDC20_ECTL_HS_CSYNC (2 << 16) +#define VIDC20_ECTL_HS_NCSYNC (3 << 16) + +#define VIDC20_ECTL_VS_MASK (3 << 18) +#define VIDC20_ECTL_VS_VSYNC (0 << 18) +#define VIDC20_ECTL_VS_NVSYNC (1 << 18) +#define VIDC20_ECTL_VS_CSYNC (2 << 18) +#define VIDC20_ECTL_VS_NCSYNC (3 << 18) + +#define VIDC20_DCTL 0xf0000000 +/* 0-9 = number of words in scanline */ +#define VIDC20_DCTL_SNA (1 << 12) +#define VIDC20_DCTL_HDIS (1 << 13) +#define VIDC20_DCTL_BUS_NS (0 << 16) +#define VIDC20_DCTL_BUS_D31_0 (1 << 16) +#define VIDC20_DCTL_BUS_D63_32 (2 << 16) +#define VIDC20_DCTL_BUS_D63_0 (3 << 16) +#define VIDC20_DCTL_VRAM_DIS (0 << 18) +#define VIDC20_DCTL_VRAM_PXCLK (1 << 18) +#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18) +#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18) + +#endif diff --git a/drivers/video/fbdev/amifb.c b/drivers/video/fbdev/amifb.c new file mode 100644 index 000000000..1116a0789 --- /dev/null +++ b/drivers/video/fbdev/amifb.c @@ -0,0 +1,3787 @@ +/* + * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device + * + * Copyright (C) 1995-2003 Geert Uytterhoeven + * + * with work by Roman Zippel + * + * + * This file is based on the Atari frame buffer device (atafb.c): + * + * Copyright (C) 1994 Martin Schaller + * Roman Hodek + * + * with work by Andreas Schwab + * Guenther Kelleter + * + * and on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * + * + * History: + * + * - 24 Jul 96: Copper generates now vblank interrupt and + * VESA Power Saving Protocol is fully implemented + * - 14 Jul 96: Rework and hopefully last ECS bugs fixed + * - 7 Mar 96: Hardware sprite support by Roman Zippel + * - 18 Feb 96: OCS and ECS support by Roman Zippel + * Hardware functions completely rewritten + * - 2 Dec 95: AGA version by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "c2p.h" + + +#define DEBUG + +#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) +#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ +#endif + +#if !defined(CONFIG_FB_AMIGA_OCS) +# define IS_OCS (0) +#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_OCS (chipset == TAG_OCS) +#else +# define CONFIG_FB_AMIGA_OCS_ONLY +# define IS_OCS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_ECS) +# define IS_ECS (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_ECS (chipset == TAG_ECS) +#else +# define CONFIG_FB_AMIGA_ECS_ONLY +# define IS_ECS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_AGA) +# define IS_AGA (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) +# define IS_AGA (chipset == TAG_AGA) +#else +# define CONFIG_FB_AMIGA_AGA_ONLY +# define IS_AGA (1) +#endif + +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/******************************************************************************* + + + Generic video timings + --------------------- + + Timings used by the frame buffer interface: + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | v | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # v # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | v | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | v | | | + +----------+---------------------------------------------+----------+-------+ + + + Amiga video timings + ------------------- + + The Amiga native chipsets uses another timing scheme: + + - hsstrt: Start of horizontal synchronization pulse + - hsstop: End of horizontal synchronization pulse + - htotal: Last value on the line (i.e. line length = htotal + 1) + - vsstrt: Start of vertical synchronization pulse + - vsstop: End of vertical synchronization pulse + - vtotal: Last line value (i.e. number of lines = vtotal + 1) + - hcenter: Start of vertical retrace for interlace + + You can specify the blanking timings independently. Currently I just set + them equal to the respective synchronization values: + + - hbstrt: Start of horizontal blank + - hbstop: End of horizontal blank + - vbstrt: Start of vertical blank + - vbstop: End of vertical blank + + Horizontal values are in color clock cycles (280 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Amiga visible window definitions + -------------------------------- + + Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to + make corrections and/or additions. + + Within the above synchronization specifications, the visible window is + defined by the following parameters (actual register resolutions may be + different; all horizontal values are normalized with respect to the pixel + clock): + + - diwstrt_h: Horizontal start of the visible window + - diwstop_h: Horizontal stop + 1(*) of the visible window + - diwstrt_v: Vertical start of the visible window + - diwstop_v: Vertical stop of the visible window + - ddfstrt: Horizontal start of display DMA + - ddfstop: Horizontal stop of display DMA + - hscroll: Horizontal display output delay + + Sprite positioning: + + - sprstrt_h: Horizontal start - 4 of sprite + - sprstrt_v: Vertical start of sprite + + (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. + + Horizontal values are in dotclock cycles (35 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Dependencies (AGA, SHRES (35 ns dotclock)) + ------------------------------------------- + + Since there are much more parameters for the Amiga display than for the + frame buffer interface, there must be some dependencies among the Amiga + display parameters. Here's what I found out: + + - ddfstrt and ddfstop are best aligned to 64 pixels. + - the chipset needs 64 + 4 horizontal pixels after the DMA start before + the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want + to display the first pixel on the line too. Increase diwstrt_h for + virtual screen panning. + - the display DMA always fetches 64 pixels at a time (fmode = 3). + - ddfstop is ddfstrt+#pixels - 64. + - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can + be 1 more than htotal. + - hscroll simply adds a delay to the display output. Smooth horizontal + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. + - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane + DMA, so it's best to make the DMA start as late as possible. + - you really don't want to make ddfstrt < 128, since this will steal DMA + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + - I make diwstop_h and diwstop_v as large as possible. + + General dependencies + -------------------- + + - all values are SHRES pixel (35ns) + + table 1:fetchstart table 2:prefetch table 3:fetchsize + ------------------ ---------------- ----------------- + Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES + -------------#------+-----+------#------+-----+------#------+-----+------ + Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 + Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 + Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 + + - chipset needs 4 pixels before the first pixel is output + - ddfstrt must be aligned to fetchstart (table 1) + - chipset needs also prefetch (table 2) to get first pixel data, so + ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch + - for horizontal panning decrease diwstrt_h + - the length of a fetchline must be aligned to fetchsize (table 3) + - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit + moved to optimize use of dma (useful for OCS/ECS overscan displays) + - ddfstop is ddfstrt + ddfsize - fetchsize + - If C= didn't change anything for AGA, then at following positions the + dma bus is already used: + ddfstrt < 48 -> memory refresh + < 96 -> disk dma + < 160 -> audio dma + < 192 -> sprite 0 dma + < 416 -> sprite dma (32 per sprite) + - in accordance with the hardware reference manual a hardware stop is at + 192, but AGA (ECS?) can go below this. + + DMA priorities + -------------- + + Since there are limits on the earliest start value for display DMA and the + display of sprites, I use the following policy on horizontal panning and + the hardware cursor: + + - if you want to start display DMA too early, you lose the ability to + do smooth horizontal panning (xpanstep 1 -> 64). + - if you want to go even further, you lose the hardware cursor too. + + IMHO a hardware cursor is more important for X than horizontal scrolling, + so that's my motivation. + + + Implementation + -------------- + + ami_decode_var() converts the frame buffer values to the Amiga values. It's + just a `straightforward' implementation of the above rules. + + + Standard VGA timings + -------------------- + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + 80x25 720 400 27 45 35 12 108 2 + 80x30 720 480 27 45 30 9 108 2 + + These were taken from a XFree86 configuration file, recalculated for a 28 MHz + dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer + generic timings. + + As a comparison, graphics/monitor.h suggests the following: + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + + VGA 640 480 52 112 24 19 112 - 2 + + VGA70 640 400 52 112 27 21 112 - 2 - + + + Sync polarities + --------------- + + VSYNC HSYNC Vertical size Vertical total + ----- ----- ------------- -------------- + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 + + Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 + + + Broadcast video timings + ----------------------- + + According to the CCIR and RETMA specifications, we have the following values: + + CCIR -> PAL + ----------- + + - a scanline is 64 µs long, of which 52.48 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 625 scanlines, of which 575 are visible (interlaced); after + rounding this becomes 576. + + RETMA -> NTSC + ------------- + + - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 525 scanlines, of which 485 are visible (interlaced); after + rounding this becomes 484. + + Thus if you want a PAL compatible display, you have to do the following: + + - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast + timings are to be used. + - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an + interlaced, 312 for a non-interlaced and 156 for a doublescanned + display. + - make sure left_margin + xres + right_margin + hsync_len = 1816 for a + SHRES, 908 for a HIRES and 454 for a LORES display. + - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), + left_margin + 2 * hsync_len must be greater or equal. + - the upper visible part begins at 48 (interlaced; non-interlaced:24, + doublescanned:12), upper_margin + 2 * vsync_len must be greater or + equal. + - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync + of 4 scanlines + + The settings for a NTSC compatible display are straightforward. + + Note that in a strict sense the PAL and NTSC standards only define the + encoding of the color part (chrominance) of the video signal and don't say + anything about horizontal/vertical synchronization nor refresh rates. + + + -- Geert -- + +*******************************************************************************/ + + + /* + * Custom Chipset Definitions + */ + +#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) + + /* + * BPLCON0 -- Bitplane Control Register 0 + */ + +#define BPC0_HIRES (0x8000) +#define BPC0_BPU2 (0x4000) /* Bit plane used count */ +#define BPC0_BPU1 (0x2000) +#define BPC0_BPU0 (0x1000) +#define BPC0_HAM (0x0800) /* HAM mode */ +#define BPC0_DPF (0x0400) /* Double playfield */ +#define BPC0_COLOR (0x0200) /* Enable colorburst */ +#define BPC0_GAUD (0x0100) /* Genlock audio enable */ +#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ +#define BPC0_SHRES (0x0040) /* Super hi res mode */ +#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ +#define BPC0_BPU3 (0x0010) /* AGA */ +#define BPC0_LPEN (0x0008) /* Light pen enable */ +#define BPC0_LACE (0x0004) /* Interlace */ +#define BPC0_ERSY (0x0002) /* External resync */ +#define BPC0_ECSENA (0x0001) /* ECS enable */ + + /* + * BPLCON2 -- Bitplane Control Register 2 + */ + +#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ +#define BPC2_ZDBPSEL1 (0x2000) +#define BPC2_ZDBPSEL0 (0x1000) +#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ +#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ +#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ +#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ +#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ +#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ +#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ +#define BPC2_PF2P1 (0x0010) +#define BPC2_PF2P0 (0x0008) +#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ +#define BPC2_PF1P1 (0x0002) +#define BPC2_PF1P0 (0x0001) + + /* + * BPLCON3 -- Bitplane Control Register 3 (AGA) + */ + +#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ +#define BPC3_BANK1 (0x4000) +#define BPC3_BANK0 (0x2000) +#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ +#define BPC3_PF2OF1 (0x0800) +#define BPC3_PF2OF0 (0x0400) +#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ +#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ +#define BPC3_SPRES0 (0x0040) +#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ +#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ +#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ +#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ +#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ + + /* + * BPLCON4 -- Bitplane Control Register 4 (AGA) + */ + +#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ +#define BPC4_BPLAM6 (0x4000) +#define BPC4_BPLAM5 (0x2000) +#define BPC4_BPLAM4 (0x1000) +#define BPC4_BPLAM3 (0x0800) +#define BPC4_BPLAM2 (0x0400) +#define BPC4_BPLAM1 (0x0200) +#define BPC4_BPLAM0 (0x0100) +#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ +#define BPC4_ESPRM6 (0x0040) +#define BPC4_ESPRM5 (0x0020) +#define BPC4_ESPRM4 (0x0010) +#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ +#define BPC4_OSPRM6 (0x0004) +#define BPC4_OSPRM5 (0x0002) +#define BPC4_OSPRM4 (0x0001) + + /* + * BEAMCON0 -- Beam Control Register + */ + +#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ +#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ +#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ +#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ +#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ +#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ +#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ +#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ +#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ +#define BMC0_PAL (0x0020) /* Set decodes for PAL */ +#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ +#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ +#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ +#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ +#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ + + + /* + * FMODE -- Fetch Mode Control Register (AGA) + */ + +#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ +#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ +#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ +#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ +#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ +#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ + + /* + * Tags used to indicate a specific Pixel Clock + * + * clk_shift is the shift value to get the timings in 35 ns units + */ + +enum { TAG_SHRES, TAG_HIRES, TAG_LORES }; + + /* + * Tags used to indicate the specific chipset + */ + +enum { TAG_OCS, TAG_ECS, TAG_AGA }; + + /* + * Tags used to indicate the memory bandwidth + */ + +enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; + + + /* + * Clock Definitions, Maximum Display Depth + * + * These depend on the E-Clock or the Chipset, so they are filled in + * dynamically + */ + +static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxfmode, chipset; + + + /* + * Broadcast Video Timings + * + * Horizontal values are in 35 ns (SHRES) units + * Vertical values are in interlaced scanlines + */ + +#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ +#define PAL_DIWSTRT_V (48) +#define PAL_HTOTAL (1816) +#define PAL_VTOTAL (625) + +#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ +#define NTSC_DIWSTRT_V (40) +#define NTSC_HTOTAL (1816) +#define NTSC_VTOTAL (525) + + + /* + * Various macros + */ + +#define up2(v) (((v) + 1) & -2) +#define down2(v) ((v) & -2) +#define div2(v) ((v)>>1) +#define mod2(v) ((v) & 1) + +#define up4(v) (((v) + 3) & -4) +#define down4(v) ((v) & -4) +#define mul4(v) ((v) << 2) +#define div4(v) ((v)>>2) +#define mod4(v) ((v) & 3) + +#define up8(v) (((v) + 7) & -8) +#define down8(v) ((v) & -8) +#define div8(v) ((v)>>3) +#define mod8(v) ((v) & 7) + +#define up16(v) (((v) + 15) & -16) +#define down16(v) ((v) & -16) +#define div16(v) ((v)>>4) +#define mod16(v) ((v) & 15) + +#define up32(v) (((v) + 31) & -32) +#define down32(v) ((v) & -32) +#define div32(v) ((v)>>5) +#define mod32(v) ((v) & 31) + +#define up64(v) (((v) + 63) & -64) +#define down64(v) ((v) & -64) +#define div64(v) ((v)>>6) +#define mod64(v) ((v) & 63) + +#define upx(x, v) (((v) + (x) - 1) & -(x)) +#define downx(x, v) ((v) & -(x)) +#define modx(x, v) ((v) & ((x) - 1)) + +/* + * FIXME: Use C variants of the code marked with #ifdef __mc68000__ + * in the driver. It shouldn't negatively affect the performance and + * is required for APUS support (once it is re-added to the kernel). + * Needs to be tested on the hardware though.. + */ +/* if x1 is not a constant, this macro won't make real sense :-) */ +#ifdef __mc68000__ +#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ + "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) +#else +/* We know a bit about the numbers, so we can do it this way */ +#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ + ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2)) +#endif + +#define highw(x) ((u_long)(x)>>16 & 0xffff) +#define loww(x) ((u_long)(x) & 0xffff) + +#define custom amiga_custom + +#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER +#define VBlankOff() custom.intena = IF_COPER + + + /* + * Chip RAM we reserve for the Frame Buffer + * + * This defines the Maximum Virtual Screen Size + * (Setable per kernel options?) + */ + +#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ +#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ +#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ +#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ +#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ + +#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ +#define DUMMYSPRITEMEMSIZE (8) +static u_long spritememory; + +#define CHIPRAM_SAFETY_LIMIT (16384) + +static u_long videomemory; + + /* + * This is the earliest allowed start of fetching display data. + * Only if you really want no hardware cursor and audio, + * set this to 128, but let it better at 192 + */ + +static u_long min_fstrt = 192; + +#define assignchunk(name, type, ptr, size) \ +{ \ + (name) = (type)(ptr); \ + ptr += size; \ +} + + + /* + * Copper Instructions + */ + +#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) +#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) +#define CEND (0xfffffffe) + + +typedef union { + u_long l; + u_short w[2]; +} copins; + +static struct copdisplay { + copins *init; + copins *wait; + copins *list[2][2]; + copins *rebuild[2]; +} copdisplay; + +static u_short currentcop = 0; + + /* + * Hardware Cursor API Definitions + * These used to be in linux/fb.h, but were preliminary and used by + * amifb only anyway + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + __u16 crsr_width; /* width and height of the cursor in */ + __u16 crsr_height; /* pixels (zero if no cursor) */ + __u16 crsr_xsize; /* cursor size in display pixels */ + __u16 crsr_ysize; + __u16 crsr_color1; /* colormap entry for cursor color1 */ + __u16 crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + __u16 width; + __u16 height; + __u16 xspot; + __u16 yspot; + DECLARE_FLEX_ARRAY(__u8, data); /* field with [height][width] */ +}; + +struct fb_cursorstate { + __s16 xoffset; + __s16 yoffset; + __u16 mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + + + /* + * Hardware Cursor + */ + +static int cursorrate = 20; /* Number of frames/flash toggle */ +static u_short cursorstate = -1; +static u_short cursormode = FB_CURSOR_OFF; + +static u_short *lofsprite, *shfsprite, *dummysprite; + + /* + * Current Video Mode + */ + +struct amifb_par { + + /* General Values */ + + int xres; /* vmode */ + int yres; /* vmode */ + int vxres; /* vmode */ + int vyres; /* vmode */ + int xoffset; /* vmode */ + int yoffset; /* vmode */ + u_short bpp; /* vmode */ + u_short clk_shift; /* vmode */ + u_short line_shift; /* vmode */ + int vmode; /* vmode */ + u_short diwstrt_h; /* vmode */ + u_short diwstop_h; /* vmode */ + u_short diwstrt_v; /* vmode */ + u_short diwstop_v; /* vmode */ + u_long next_line; /* modulo for next line */ + u_long next_plane; /* modulo for next plane */ + + /* Cursor Values */ + + struct { + short crsr_x; /* movecursor */ + short crsr_y; /* movecursor */ + short spot_x; + short spot_y; + u_short height; + u_short width; + u_short fmode; + } crsr; + + /* OCS Hardware Registers */ + + u_long bplpt0; /* vmode, pan (Note: physical address) */ + u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ + u_short ddfstrt; + u_short ddfstop; + u_short bpl1mod; + u_short bpl2mod; + u_short bplcon0; /* vmode */ + u_short bplcon1; /* vmode */ + u_short htotal; /* vmode */ + u_short vtotal; /* vmode */ + + /* Additional ECS Hardware Registers */ + + u_short bplcon3; /* vmode */ + u_short beamcon0; /* vmode */ + u_short hsstrt; /* vmode */ + u_short hsstop; /* vmode */ + u_short hbstrt; /* vmode */ + u_short hbstop; /* vmode */ + u_short vsstrt; /* vmode */ + u_short vsstop; /* vmode */ + u_short vbstrt; /* vmode */ + u_short vbstop; /* vmode */ + u_short hcenter; /* vmode */ + + /* Additional AGA Hardware Registers */ + + u_short fmode; /* vmode */ +}; + + + /* + * Saved color entry 0 so we can restore it when unblanking + */ + +static u_char red0, green0, blue0; + + +#if defined(CONFIG_FB_AMIGA_ECS) +static u_short ecs_palette[32]; +#endif + + + /* + * Latches for Display Changes during VBlank + */ + +static u_short do_vmode_full = 0; /* Change the Video Mode */ +static u_short do_vmode_pan = 0; /* Update the Video Mode */ +static short do_blank = 0; /* (Un)Blank the Screen (±1) */ +static u_short do_cursor = 0; /* Move the Cursor */ + + + /* + * Various Flags + */ + +static u_short is_blanked = 0; /* Screen is Blanked */ +static u_short is_lace = 0; /* Screen is laced */ + + /* + * Predefined Video Modes + * + */ + +static struct fb_videomode ami_modedb[] __initdata = { + + /* + * AmigaOS Video Modes + * + * If you change these, make sure to update DEFMODE_* as well! + */ + + { + /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x480, 29 kHz, 57 Hz */ + "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x960, 29 kHz, 57 Hz interlaced */ + "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 15 kHz, 72 Hz */ + "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, + 10, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 29 kHz, 68 Hz */ + "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 29 kHz, 68 Hz interlaced */ + "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 800x300, 23 kHz, 70 Hz */ + "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 800x600, 23 kHz, 70 Hz interlaced */ + "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x512, 27 kHz, 47 Hz */ + "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x1024, 27 kHz, 47 Hz interlaced */ + "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 31 kHz, 70 Hz (VGA) */ + "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, + FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, + +#if 0 + + /* + * A2024 video modes + * These modes don't work yet because there's no A2024 driver. + */ + + { + /* 1024x800, 10 Hz */ + "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 1024x800, 15 Hz */ + "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + } +#endif +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb) + +static char *mode_option __initdata = NULL; +static int round_down_bpp = 1; /* for mode probing */ + + /* + * Some default modes + */ + + +#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */ +#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */ +#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */ +#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */ +#define DEFMODE_AGA 19 /* "vga70" for AGA */ + + +static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ + +static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ +static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ +static u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ +static u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ + + + /* + * Macros for the conversion from real world values to hardware register + * values + * + * This helps us to keep our attention on the real stuff... + * + * Hardware limits for AGA: + * + * parameter min max step + * --------- --- ---- ---- + * diwstrt_h 0 2047 1 + * diwstrt_v 0 2047 1 + * diwstop_h 0 4095 1 + * diwstop_v 0 4095 1 + * + * ddfstrt 0 2032 16 + * ddfstop 0 2032 16 + * + * htotal 8 2048 8 + * hsstrt 0 2040 8 + * hsstop 0 2040 8 + * vtotal 1 4096 1 + * vsstrt 0 4095 1 + * vsstop 0 4095 1 + * hcenter 0 2040 8 + * + * hbstrt 0 2047 1 + * hbstop 0 2047 1 + * vbstrt 0 4095 1 + * vbstop 0 4095 1 + * + * Horizontal values are in 35 ns (SHRES) pixels + * Vertical values are in half scanlines + */ + +/* bplcon1 (smooth scrolling) */ + +#define hscroll2hw(hscroll) \ + (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ + ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ + ((hscroll)>>2 & 0x000f)) + +/* diwstrt/diwstop/diwhigh (visible display window) */ + +#define diwstrt2hw(diwstrt_h, diwstrt_v) \ + (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) +#define diwstop2hw(diwstop_h, diwstop_v) \ + (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) +#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ + (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ + ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ + ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) + +/* ddfstrt/ddfstop (display DMA) */ + +#define ddfstrt2hw(ddfstrt) div8(ddfstrt) +#define ddfstop2hw(ddfstop) div8(ddfstop) + +/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ + +#define hsstrt2hw(hsstrt) (div8(hsstrt)) +#define hsstop2hw(hsstop) (div8(hsstop)) +#define htotal2hw(htotal) (div8(htotal) - 1) +#define vsstrt2hw(vsstrt) (div2(vsstrt)) +#define vsstop2hw(vsstop) (div2(vsstop)) +#define vtotal2hw(vtotal) (div2(vtotal) - 1) +#define hcenter2hw(htotal) (div8(htotal)) + +/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ + +#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define vbstrt2hw(vbstrt) (div2(vbstrt)) +#define vbstop2hw(vbstop) (div2(vbstop)) + +/* colour */ + +#define rgb2hw8_high(red, green, blue) \ + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) +#define rgb2hw8_low(red, green, blue) \ + (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) +#define rgb2hw4(red, green, blue) \ + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) +#define rgb2hw2(red, green, blue) \ + (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) + +/* sprpos/sprctl (sprite positioning) */ + +#define spr2hw_pos(start_v, start_h) \ + (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) +#define spr2hw_ctl(start_v, start_h, stop_v) \ + (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ + ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ + ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ + ((start_h)>>2 & 0x0001)) + +/* get current vertical position of beam */ +#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) + + /* + * Copper Initialisation List + */ + +#define COPINITSIZE (sizeof(copins) * 40) + +enum { + cip_bplcon0 +}; + + /* + * Long Frame/Short Frame Copper List + * Don't change the order, build_copper()/rebuild_copper() rely on this + */ + +#define COPLISTSIZE (sizeof(copins) * 64) + +enum { + cop_wait, cop_bplcon0, + cop_spr0ptrh, cop_spr0ptrl, + cop_diwstrt, cop_diwstop, + cop_diwhigh, +}; + + /* + * Pixel modes for Bitplanes and Sprites + */ + +static u_short bplpixmode[3] = { + BPC0_SHRES, /* 35 ns */ + BPC0_HIRES, /* 70 ns */ + 0 /* 140 ns */ +}; + +static u_short sprpixmode[3] = { + BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ + BPC3_SPRES1, /* 70 ns */ + BPC3_SPRES0 /* 140 ns */ +}; + + /* + * Fetch modes for Bitplanes and Sprites + */ + +static u_short bplfetchmode[3] = { + 0, /* 1x */ + FMODE_BPL32, /* 2x */ + FMODE_BPAGEM | FMODE_BPL32 /* 4x */ +}; + +static u_short sprfetchmode[3] = { + 0, /* 1x */ + FMODE_SPR32, /* 2x */ + FMODE_SPAGEM | FMODE_SPR32 /* 4x */ +}; + + +/* --------------------------- Hardware routines --------------------------- */ + + /* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, + const struct fb_info *info) +{ + u_short clk_shift, line_shift; + u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; + u_int htotal, vtotal; + + /* + * Find a matching Pixel Clock + */ + + for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift > TAG_LORES) { + DPRINTK("pixclock too high\n"); + return -EINVAL; + } + par->clk_shift = clk_shift; + + /* + * Check the Geometry Values + */ + + if ((par->xres = var->xres) < 64) + par->xres = 64; + if ((par->yres = var->yres) < 64) + par->yres = 64; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + par->bpp = var->bits_per_pixel; + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + if (par->bpp > maxdepth[clk_shift]) { + if (round_down_bpp && maxdepth[clk_shift]) + par->bpp = maxdepth[clk_shift]; + else { + DPRINTK("invalid bpp\n"); + return -EINVAL; + } + } + } else if (var->nonstd == FB_NONSTD_HAM) { + if (par->bpp < 6) + par->bpp = 6; + if (par->bpp != 6) { + if (par->bpp < 8) + par->bpp = 8; + if (par->bpp != 8 || !IS_AGA) { + DPRINTK("invalid bpp for ham mode\n"); + return -EINVAL; + } + } + } else { + DPRINTK("unknown nonstd mode\n"); + return -EINVAL; + } + + /* + * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following + * checks failed and smooth scrolling is not possible + */ + + par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line_shift = 0; + break; + case FB_VMODE_NONINTERLACED: + line_shift = 1; + break; + case FB_VMODE_DOUBLE: + if (!IS_AGA) { + DPRINTK("double mode only possible with aga\n"); + return -EINVAL; + } + line_shift = 2; + break; + default: + DPRINTK("unknown video mode\n"); + return -EINVAL; + break; + } + par->line_shift = line_shift; + + /* + * Vertical and Horizontal Timings + */ + + xres_n = par->xres << clk_shift; + yres_n = par->yres << line_shift; + par->htotal = down8((var->left_margin + par->xres + var->right_margin + + var->hsync_len) << clk_shift); + par->vtotal = + down2(((var->upper_margin + par->yres + var->lower_margin + + var->vsync_len) << line_shift) + 1); + + if (IS_AGA) + par->bplcon3 = sprpixmode[clk_shift]; + else + par->bplcon3 = 0; + if (var->sync & FB_SYNC_BROADCAST) { + par->diwstop_h = par->htotal - + ((var->right_margin - var->hsync_len) << clk_shift); + if (IS_AGA) + par->diwstop_h += mod4(var->hsync_len); + else + par->diwstop_h = down4(par->diwstop_h); + + par->diwstrt_h = par->diwstop_h - xres_n; + par->diwstop_v = par->vtotal - + ((var->lower_margin - var->vsync_len) << line_shift); + par->diwstrt_v = par->diwstop_v - yres_n; + if (par->diwstop_h >= par->htotal + 8) { + DPRINTK("invalid diwstop_h\n"); + return -EINVAL; + } + if (par->diwstop_v > par->vtotal) { + DPRINTK("invalid diwstop_v\n"); + return -EINVAL; + } + + if (!IS_OCS) { + /* Initialize sync with some reasonable values for pwrsave */ + par->hsstrt = 160; + par->hsstop = 320; + par->vsstrt = 30; + par->vsstop = 34; + } else { + par->hsstrt = 0; + par->hsstop = 0; + par->vsstrt = 0; + par->vsstop = 0; + } + if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { + /* PAL video mode */ + if (par->htotal != PAL_HTOTAL) { + DPRINTK("htotal invalid for pal\n"); + return -EINVAL; + } + if (par->diwstrt_h < PAL_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for pal\n"); + return -EINVAL; + } + if (par->diwstrt_v < PAL_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for pal\n"); + return -EINVAL; + } + htotal = PAL_HTOTAL>>clk_shift; + vtotal = PAL_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = BMC0_PAL; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = BMC0_PAL; + par->hsstop = 1; + } else if (amiga_vblank != 50) { + DPRINTK("pal not supported by this chipset\n"); + return -EINVAL; + } + } else { + /* NTSC video mode + * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK + * and NTSC activated, so than better let diwstop_h <= 1812 + */ + if (par->htotal != NTSC_HTOTAL) { + DPRINTK("htotal invalid for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_h < NTSC_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_v < NTSC_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for ntsc\n"); + return -EINVAL; + } + htotal = NTSC_HTOTAL>>clk_shift; + vtotal = NTSC_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = 0; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = 0; + par->hsstop = 1; + } else if (amiga_vblank != 60) { + DPRINTK("ntsc not supported by this chipset\n"); + return -EINVAL; + } + } + if (IS_OCS) { + if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || + par->diwstrt_v >= 512 || par->diwstop_v < 256) { + DPRINTK("invalid position for display on ocs\n"); + return -EINVAL; + } + } + } else if (!IS_OCS) { + /* Programmable video mode */ + par->hsstrt = var->right_margin << clk_shift; + par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; + par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); + if (!IS_AGA) + par->diwstop_h = down4(par->diwstop_h) - 16; + par->diwstrt_h = par->diwstop_h - xres_n; + par->hbstop = par->diwstrt_h + 4; + par->hbstrt = par->diwstop_h + 4; + if (par->hbstrt >= par->htotal + 8) + par->hbstrt -= par->htotal; + par->hcenter = par->hsstrt + (par->htotal >> 1); + par->vsstrt = var->lower_margin << line_shift; + par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; + par->diwstop_v = par->vtotal; + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + par->diwstop_v -= 2; + par->diwstrt_v = par->diwstop_v - yres_n; + par->vbstop = par->diwstrt_v - 2; + par->vbstrt = par->diwstop_v - 2; + if (par->vtotal > 2048) { + DPRINTK("vtotal too high\n"); + return -EINVAL; + } + if (par->htotal > 2048) { + DPRINTK("htotal too high\n"); + return -EINVAL; + } + par->bplcon3 |= BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + htotal = par->htotal>>clk_shift; + vtotal = par->vtotal>>1; + } else { + DPRINTK("only broadcast modes possible for ocs\n"); + return -EINVAL; + } + + /* + * Checking the DMA timing + */ + + fconst = 16 << maxfmode << clk_shift; + + /* + * smallest window start value without turn off other dma cycles + * than sprite1-7, unless you change min_fstrt + */ + + + fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); + fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; + if (fstrt < min_fstrt) { + DPRINTK("fetch start too low\n"); + return -EINVAL; + } + + /* + * smallest window start value where smooth scrolling is possible + */ + + fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - + fsize; + if (fstrt < min_fstrt) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + maxfetchstop = down16(par->htotal - 80); + + fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; + fsize = upx(fconst, xres_n + + modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); + if (fstrt + fsize > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = upx(fconst, xres_n); + if (fstrt + fsize > maxfetchstop) { + DPRINTK("fetch stop too high\n"); + return -EINVAL; + } + + if (maxfmode + clk_shift <= 1) { + fsize = up64(xres_n + fconst - 1); + if (min_fstrt + fsize - 64 > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = up64(xres_n); + if (min_fstrt + fsize - 64 > maxfetchstop) { + DPRINTK("fetch size too high\n"); + return -EINVAL; + } + + fsize -= 64; + } else + fsize -= fconst; + + /* + * Check if there is enough time to update the bitplane pointers for ywrap + */ + + if (par->htotal - fsize - 64 < par->bpp * 64) + par->vmode &= ~FB_VMODE_YWRAP; + + /* + * Bitplane calculations and check the Memory Requirements + */ + + if (amifb_ilbm) { + par->next_plane = div8(upx(16 << maxfmode, par->vxres)); + par->next_line = par->bpp * par->next_plane; + if (par->next_line * par->vyres > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } else { + par->next_line = div8(upx(16 << maxfmode, par->vxres)); + par->next_plane = par->vyres * par->next_line; + if (par->next_plane * par->bpp > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; + if (!IS_OCS) + par->bplcon0 |= BPC0_ECSENA; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp << 12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + + if (IS_AGA) + par->fmode = bplfetchmode[maxfmode]; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + if (IS_AGA) + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset >= par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || + par->yoffset > par->vyres - par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + par->crsr.crsr_x = par->crsr.crsr_y = 0; + par->crsr.spot_x = par->crsr.spot_y = 0; + par->crsr.height = par->crsr.width = 0; + + return 0; +} + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static void ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) +{ + u_short clk_shift, line_shift; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + clk_shift = par->clk_shift; + line_shift = par->line_shift; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red.offset = 0; + var->red.msb_right = 0; + var->red.length = par->bpp; + if (par->bplcon0 & BPC0_HAM) + var->red.length -= 2; + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->pixclock = pixclock[clk_shift]; + + if (IS_AGA && par->fmode & FMODE_BSCAN2) + var->vmode = FB_VMODE_DOUBLE; + else if (par->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { + var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; + var->right_margin = par->hsstrt>>clk_shift; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; + var->lower_margin = par->vsstrt>>line_shift; + var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; + var->sync = 0; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + } else { + var->sync = FB_SYNC_BROADCAST; + var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); + var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = 4>>line_shift; + var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; + var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - + var->lower_margin - var->vsync_len; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; +} + + + /* + * Update hardware + */ + +static void ami_update_par(struct fb_info *info) +{ + struct amifb_par *par = info->par; + short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; + + clk_shift = par->clk_shift; + + if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) + par->xoffset = upx(16 << maxfmode, par->xoffset); + + fconst = 16 << maxfmode << clk_shift; + vshift = modx(16 << maxfmode, par->xoffset); + fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; + fsize = (par->xres + vshift) << clk_shift; + shift = modx(fconst, fstrt); + move = downx(2 << maxfmode, div8(par->xoffset)); + if (maxfmode + clk_shift > 1) { + fstrt = downx(fconst, fstrt) - 64; + fsize = upx(fconst, fsize); + fstop = fstrt + fsize - fconst; + } else { + mod = fstrt = downx(fconst, fstrt) - fconst; + fstop = fstrt + upx(fconst, fsize) - 64; + fsize = up64(fsize); + fstrt = fstop - fsize + 64; + if (fstrt < min_fstrt) { + fstop += min_fstrt - fstrt; + fstrt = min_fstrt; + } + move = move - div8((mod - fstrt)>>clk_shift); + } + mod = par->next_line - div8(fsize>>clk_shift); + par->ddfstrt = fstrt; + par->ddfstop = fstop; + par->bplcon1 = hscroll2hw(shift); + par->bpl2mod = mod; + if (par->bplcon0 & BPC0_LACE) + par->bpl2mod += par->next_line; + if (IS_AGA && (par->fmode & FMODE_BSCAN2)) + par->bpl1mod = -div8(fsize>>clk_shift); + else + par->bpl1mod = par->bpl2mod; + + if (par->yoffset) { + par->bplpt0 = info->fix.smem_start + + par->next_line * par->yoffset + move; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset > par->vyres - par->yres) { + par->bplpt0wrap = info->fix.smem_start + move; + if (par->bplcon0 & BPC0_LACE && + mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + par->bplpt0wrap += par->next_line; + } + } + } else + par->bplpt0 = info->fix.smem_start + move; + + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) + par->bplpt0 += par->next_line; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct amifb_par *par = info->par; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + ami_update_par(info); + do_vmode_pan = 1; +} + + +static void ami_update_display(const struct amifb_par *par) +{ + custom.bplcon1 = par->bplcon1; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.ddfstrt = ddfstrt2hw(par->ddfstrt); + custom.ddfstop = ddfstop2hw(par->ddfstop); +} + + /* + * Change the video mode (called by VBlank interrupt) + */ + +static void ami_init_display(const struct amifb_par *par) +{ + int i; + + custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; + custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; + if (!IS_OCS) { + custom.bplcon3 = par->bplcon3; + if (IS_AGA) + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = htotal2hw(par->htotal); + custom.hbstrt = hbstrt2hw(par->hbstrt); + custom.hbstop = hbstop2hw(par->hbstop); + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.hcenter = hcenter2hw(par->hcenter); + custom.vtotal = vtotal2hw(par->vtotal); + custom.vbstrt = vbstrt2hw(par->vbstrt); + custom.vbstop = vbstop2hw(par->vbstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + } + } + if (!IS_OCS || par->hsstop) + custom.beamcon0 = par->beamcon0; + if (IS_AGA) + custom.fmode = par->fmode; + + /* + * The minimum period for audio depends on htotal + */ + + amiga_audio_min_period = div16(par->htotal); + + is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; +#if 1 + if (is_lace) { + i = custom.vposr >> 15; + } else { + custom.vposw = custom.vposr | 0x8000; + i = 1; + } +#else + i = 1; + custom.vposw = custom.vposr | 0x8000; +#endif + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); +} + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +static void ami_do_blank(const struct amifb_par *par) +{ +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = par->bplcon3; +#endif + u_char red, green, blue; + + if (do_blank > 0) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (!IS_OCS && do_blank > 1) { + switch (do_blank) { + case FB_BLANK_VSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + case FB_BLANK_HSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstrt2hw(par->vsstop); + break; + case FB_BLANK_POWERDOWN: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + } + if (!(par->beamcon0 & BMC0_VARBEAMEN)) { + custom.htotal = htotal2hw(par->htotal); + custom.vtotal = vtotal2hw(par->vtotal); + custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; + } + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + red = red0; + green = green0; + blue = blue0; + if (!IS_OCS) { + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + custom.beamcon0 = par->beamcon0; + } + } +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else +#endif + custom.color[0] = rgb2hw4(red, green, blue); + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, + const struct amifb_par *par) +{ + fix->crsr_width = fix->crsr_xsize = par->crsr.width; + fix->crsr_height = fix->crsr_ysize = par->crsr.height; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; + return 0; +} + +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, + const struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + register u_char color; + short height, width, bits, words; + int size, alloc; + + size = par->crsr.height * par->crsr.width; + alloc = var->height * var->width; + var->height = par->crsr.height; + var->width = par->crsr.width; + var->xspot = par->crsr.spot_x; + var->yspot = par->crsr.spot_y; + if (size > var->height * var->width) + return -ENAMETOOLONG; + delta = 1 << par->crsr.fmode; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) + sspr = shfsprite + (delta << 1); + else + sspr = NULL; + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 0; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + if (bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" + : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); +#else + datawords = (*(lspr + delta) << 16) | (*lspr++); +#endif + } + --bits; +#ifdef __mc68000__ + asm volatile ( + "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " + "swap %1 ; lslw #1,%1 ; roxlb #1,%0" + : "=d" (color), "=d" (datawords) : "1" (datawords)); +#else + color = (((datawords >> 30) & 2) + | ((datawords >> 15) & 1)); + datawords <<= 1; +#endif + /* FIXME: check the return value + test the change */ + put_user(color, data++); + } + if (bits > 0) { + --words; ++lspr; + } + while (--words >= 0) + ++lspr; +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + return 0; +} + +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + u_short fmode; + short height, width, bits, words; + + if (!var->width) + return -EINVAL; + else if (var->width <= 16) + fmode = TAG_FMODE_1; + else if (var->width <= 32) + fmode = TAG_FMODE_2; + else if (var->width <= 64) + fmode = TAG_FMODE_4; + else + return -EINVAL; + if (fmode > maxfmode) + return -EINVAL; + if (!var->height) + return -EINVAL; + delta = 1 << fmode; + lofsprite = shfsprite = (u_short *)spritememory; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) { + if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 4) << fmode << 2); + shfsprite += ((var->height + 5)&-2) << fmode; + sspr = shfsprite + (delta << 1); + } else { + if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 2) << fmode << 2); + sspr = NULL; + } + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 16; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + unsigned long tdata = 0; + /* FIXME: check the return value + test the change */ + get_user(tdata, data); + data++; +#ifdef __mc68000__ + asm volatile ( + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" + : "=d" (datawords) + : "0" (datawords), "d" (tdata)); +#else + datawords = ((datawords << 1) & 0xfffefffe); + datawords |= tdata & 1; + datawords |= (tdata & 2) << (16 - 1); +#endif + if (--bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); +#else + *(lspr + delta) = (u_short) (datawords >> 16); + *lspr++ = (u_short) (datawords & 0xffff); +#endif + } + } + if (bits < 16) { + --words; +#ifdef __mc68000__ + asm volatile ( + "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " + "swap %2 ; lslw %4,%2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); +#else + *(lspr + delta) = (u_short) (datawords >> (16 + bits)); + *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); +#endif + } + while (--words >= 0) { +#ifdef __mc68000__ + asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); +#else + *(lspr + delta) = 0; + *lspr++ = 0; +#endif + } +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + par->crsr.height = var->height; + par->crsr.width = var->width; + par->crsr.spot_x = var->xspot; + par->crsr.spot_y = var->yspot; + par->crsr.fmode = fmode; + if (IS_AGA) { + par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); + par->fmode |= sprfetchmode[fmode]; + custom.fmode = par->fmode; + } + return 0; +} + +static int ami_get_cursorstate(struct fb_cursorstate *state, + const struct amifb_par *par) +{ + state->xoffset = par->crsr.crsr_x; + state->yoffset = par->crsr.crsr_y; + state->mode = cursormode; + return 0; +} + +static int ami_set_cursorstate(struct fb_cursorstate *state, + struct amifb_par *par) +{ + par->crsr.crsr_x = state->xoffset; + par->crsr.crsr_y = state->yoffset; + if ((cursormode = state->mode) == FB_CURSOR_OFF) + cursorstate = -1; + do_cursor = 1; + return 0; +} + +static void ami_set_sprite(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short hs, vs, ve; + u_long pl, ps; + short mx, my; + + cops = copdisplay.list[currentcop][0]; + copl = copdisplay.list[currentcop][1]; + ps = pl = ZTWO_PADDR(dummysprite); + mx = par->crsr.crsr_x - par->crsr.spot_x; + my = par->crsr.crsr_y - par->crsr.spot_y; + if (!(par->vmode & FB_VMODE_YWRAP)) { + mx -= par->xoffset; + my -= par->yoffset; + } + if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && + mx > -(short)par->crsr.width && mx < par->xres && + my > -(short)par->crsr.height && my < par->yres) { + pl = ZTWO_PADDR(lofsprite); + hs = par->diwstrt_h + (mx << par->clk_shift) - 4; + vs = par->diwstrt_v + (my << par->line_shift); + ve = vs + (par->crsr.height << par->line_shift); + if (par->bplcon0 & BPC0_LACE) { + ps = ZTWO_PADDR(shfsprite); + lofsprite[0] = spr2hw_pos(vs, hs); + shfsprite[0] = spr2hw_pos(vs + 1, hs); + if (mod2(vs)) { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); + swap(pl, ps); + } else { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); + } + } else { + lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + } + } + copl[cop_spr0ptrh].w[1] = highw(pl); + copl[cop_spr0ptrl].w[1] = loww(pl); + if (par->bplcon0 & BPC0_LACE) { + cops[cop_spr0ptrh].w[1] = highw(ps); + cops[cop_spr0ptrl].w[1] = loww(ps); + } +} + + + /* + * Initialise the Copper Initialisation List + */ + +static void __init ami_init_copper(void) +{ + copins *cop = copdisplay.init; + u_long p; + int i; + + if (!IS_OCS) { + (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + (cop++)->l = CMOVE(0x0181, diwstrt); + (cop++)->l = CMOVE(0x0281, diwstop); + (cop++)->l = CMOVE(0x0000, diwhigh); + } else + (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); + p = ZTWO_PADDR(dummysprite); + for (i = 0; i < 8; i++) { + (cop++)->l = CMOVE(0, spr[i].pos); + (cop++)->l = CMOVE(highw(p), sprpt[i]); + (cop++)->l = CMOVE2(loww(p), sprpt[i]); + } + + (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); + copdisplay.wait = cop; + (cop++)->l = CEND; + (cop++)->l = CMOVE(0, copjmp2); + cop->l = CEND; + + custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); + custom.copjmp1 = 0; +} + +static void ami_reinit_copper(const struct amifb_par *par) +{ + copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; + copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); +} + + + /* + * Rebuild the Copper List + * + * We only change the things that are not static + */ + +static void ami_rebuild_copper(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short line, h_end1, h_end2; + short i; + u_long p; + + if (IS_AGA && maxfmode + par->clk_shift == 0) + h_end1 = par->diwstrt_h - 64; + else + h_end1 = par->htotal - 32; + h_end2 = par->ddfstop + 64; + + ami_set_sprite(par); + + copl = copdisplay.rebuild[1]; + p = par->bplpt0; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; + while (line >= 512) { + (copl++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (copl++)->l = CWAIT(h_end1, line); + else + (copl++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + } + } else + p = par->bplpt0wrap; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + copl->l = CEND; + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.rebuild[0]; + p = par->bplpt0; + if (mod2(par->diwstrt_v)) + p -= par->next_line; + else + p += par->next_line; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres + 1) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; + while (line >= 512) { + (cops++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (cops++)->l = CWAIT(h_end1, line); + else + (cops++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + if (mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + p -= par->next_line; + else + p += par->next_line; + } + } else + p = par->bplpt0wrap - par->next_line; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + cops->l = CEND; + } +} + + + /* + * Build the Copper List + */ + +static void ami_build_copper(struct fb_info *info) +{ + struct amifb_par *par = info->par; + copins *copl, *cops; + u_long p; + + currentcop = 1 - currentcop; + + copl = copdisplay.list[currentcop][1]; + + (copl++)->l = CWAIT(0, 10); + (copl++)->l = CMOVE(par->bplcon0, bplcon0); + (copl++)->l = CMOVE(0, sprpt[0]); + (copl++)->l = CMOVE2(0, sprpt[0]); + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.list[currentcop][0]; + + (cops++)->l = CWAIT(0, 10); + (cops++)->l = CMOVE(par->bplcon0, bplcon0); + (cops++)->l = CMOVE(0, sprpt[0]); + (cops++)->l = CMOVE2(0, sprpt[0]); + + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); + (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, + par->diwstop_h, par->diwstop_v + 1), diwhigh); + (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); + (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + p = ZTWO_PADDR(copdisplay.list[currentcop][0]); + (copl++)->l = CMOVE(highw(p), cop2lc); + (copl++)->l = CMOVE2(loww(p), cop2lc); + p = ZTWO_PADDR(copdisplay.list[currentcop][1]); + (cops++)->l = CMOVE(highw(p), cop2lc); + (cops++)->l = CMOVE2(loww(p), cop2lc); + copdisplay.rebuild[0] = cops; + } else { + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + } + copdisplay.rebuild[1] = copl; + + ami_update_par(info); + ami_rebuild_copper(info->par); +} + +#ifndef MODULE +static void __init amifb_setup_mcap(char *spec) +{ + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: ;;; + * vertical freq. in Hz + * horizontal freq. in kHz + */ + + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) + return; + if (!(p = strsep(&spec, ";")) || !*p) + return; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) + return; + if (!(p = strsep(&spec, "")) || !*p) + return; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) + return; + + amifb_hfmin = hmin; + amifb_hfmax = hmax; + amifb_vfmin = vmin; + amifb_vfmax = vmax; +} + +static int __init amifb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + fb_invert_cmaps(); + } else if (!strcmp(this_opt, "ilbm")) + amifb_ilbm = 1; + else if (!strncmp(this_opt, "monitorcap:", 11)) + amifb_setup_mcap(this_opt + 11); + else if (!strncmp(this_opt, "fstart:", 7)) + min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); + else + mode_option = this_opt; + } + + if (min_fstrt < 48) + min_fstrt = 48; + + return 0; +} +#endif + +static int amifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err; + struct amifb_par par; + + /* Validate wanted screen parameters */ + err = ami_decode_var(var, &par, info); + if (err) + return err; + + /* Encode (possibly rounded) screen parameters */ + ami_encode_var(var, &par); + return 0; +} + + +static int amifb_set_par(struct fb_info *info) +{ + struct amifb_par *par = info->par; + int error; + + do_vmode_pan = 0; + do_vmode_full = 0; + + /* Decode wanted screen parameters */ + error = ami_decode_var(&info->var, par, info); + if (error) + return error; + + /* Set new videomode */ + ami_build_copper(info); + + /* Set VBlank trigger */ + do_vmode_full = 1; + + /* Update fix for new screen parameters */ + if (par->bpp == 1) { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + } else if (amifb_ilbm) { + info->fix.type = FB_TYPE_INTERLEAVED_PLANES; + info->fix.type_aux = par->next_line; + } else { + info->fix.type = FB_TYPE_PLANES; + info->fix.type_aux = 0; + } + info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); + + if (par->vmode & FB_VMODE_YWRAP) { + info->fix.ywrapstep = 1; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->flags = FBINFO_HWACCEL_YWRAP | + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ + } else { + info->fix.ywrapstep = 0; + if (par->vmode & FB_VMODE_SMOOTH_XPAN) + info->fix.xpanstep = 1; + else + info->fix.xpanstep = 16 << maxfmode; + info->fix.ypanstep = 1; + info->flags = FBINFO_HWACCEL_YPAN; + } + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + const struct amifb_par *par = info->par; + + if (IS_AGA) { + if (regno > 255) + return 1; + } else if (par->bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + } else { + if (regno > 31) + return 1; + } + red >>= 8; + green >>= 8; + blue >>= 8; + if (!regno) { + red0 = red; + green0 = green; + blue0 = blue; + } + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * VBlank is switched off to protect bplcon3 or ecs_palette[] from + * being changed by ami_do_blank() during the VBlank. + */ + + if (regno || !is_blanked) { +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + u_short bplcon3 = par->bplcon3; + VBlankOff(); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); + custom.color[regno & 31] = rgb2hw8_high(red, green, + blue); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | + BPC3_LOCT; + custom.color[regno & 31] = rgb2hw8_low(red, green, + blue); + custom.bplcon3 = bplcon3; + VBlankOn(); + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno + 12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + regno = down16(regno) + mul4(mod4(regno)); + for (i = regno + 3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else +#endif + custom.color[regno] = rgb2hw4(red, green, blue); + } + return 0; +} + + + /* + * Blank the display. + */ + +static int amifb_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; + + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int amifb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (!(var->vmode & FB_VMODE_YWRAP)) { + /* + * TODO: There will be problems when xpan!=1, so some columns + * on the right side will never be seen + */ + if (var->xoffset + info->var.xres > + upx(16 << maxfmode, info->var.xres_virtual)) + return -EINVAL; + } + ami_pan_var(var, info); + return 0; +} + + +#if BITS_PER_LONG == 32 +#define BYTES_PER_LONG 4 +#define SHIFT_PER_LONG 5 +#elif BITS_PER_LONG == 64 +#define BYTES_PER_LONG 8 +#define SHIFT_PER_LONG 6 +#else +#define Please update me +#endif + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long comp(unsigned long a, unsigned long b, + unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + +static inline unsigned long xor(unsigned long a, unsigned long b, + unsigned long mask) +{ + return (a & mask) ^ b; +} + + + /* + * Unaligned forward bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, + int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx - src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + shift = dst_idx - src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx + n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + n -= 8; + } + while (n--) + *dst++ = *src++; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); + + if (dst_idx + n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else if (src_idx + n <= BITS_PER_LONG) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else { + // 2 source words + d0 = *src++; + d1 = *src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG - dst_idx; + } else { + // 2 source words + d1 = *src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy_rev(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx - src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + dst += (n - 1) / BITS_PER_LONG; + src += (n - 1) / BITS_PER_LONG; + if ((n - 1) % BITS_PER_LONG) { + dst_idx += (n - 1) % BITS_PER_LONG; + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= BITS_PER_LONG - 1; + src_idx += (n - 1) % BITS_PER_LONG; + src += src_idx >> SHIFT_PER_LONG; + src_idx &= BITS_PER_LONG - 1; + } + + shift = dst_idx - src_idx; + first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); + last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); + + if (!shift) { + // Same alignment for source and dest + + if ((unsigned long)dst_idx + 1 >= n) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst--; + src--; + n -= dst_idx + 1; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + n -= 8; + } + while (n--) + *dst-- = *src--; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); + + if ((unsigned long)dst_idx + 1 >= n) { + // Single destination word + if (last) + first &= last; + if (shift < 0) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else if (1 + (unsigned long)src_idx >= n) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else { + // 2 source words + d0 = *src--; + d1 = *src; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src--; + // Leading bits + if (shift < 0) { + // Single source word + *dst = comp(d0 << left, *dst, first); + dst--; + n -= dst_idx + 1; + } else { + // 2 source words + d1 = *src--; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + d0 = d1; + dst--; + n -= dst_idx + 1; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= left) { + // Single source word + *dst = comp(d0 >> right, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 >> right | d1 << left, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned forward inverting bit copy using 32-bit or 64-bit memory + * accesses + */ + +static void bitcpy_not(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx - src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + shift = dst_idx - src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx + n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(~*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(~*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + n -= 8; + } + while (n--) + *dst++ = ~*src++; + + // Trailing bits + if (last) + *dst = comp(~*src, *dst, last); + } + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); + + if (dst_idx + n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(~*src >> right, *dst, first); + } else if (src_idx + n <= BITS_PER_LONG) { + // Single source word + *dst = comp(~*src << left, *dst, first); + } else { + // 2 source words + d0 = ~*src++; + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = ~*src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG - dst_idx; + } else { + // 2 source words + d1 = ~*src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } + } + } + } +} + + + /* + * Unaligned 32-bit pattern fill using 32/64-bit memory accesses + */ + +static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); + + if (dst_idx + n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(val, *dst, first); + dst++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + n -= 8; + } + while (n--) + *dst++ = val; + + // Trailing bits + if (last) + *dst = comp(val, *dst, last); + } +} + + + /* + * Unaligned 32-bit pattern xor using 32/64-bit memory accesses + */ + +static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); + + if (dst_idx + n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = xor(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = xor(val, *dst, first); + dst++; + n -= BITS_PER_LONG - dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 4) { + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + n -= 4; + } + while (n--) + *dst++ ^= val; + + // Trailing bits + if (last) + *dst = xor(val, *dst, last); + } +} + +static inline void fill_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane * 8; + } +} + +static inline void xor_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (color) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane * 8; + } +} + + +static void amifb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct amifb_par *par = info->par; + int dst_idx, x2, y2; + unsigned long *dst; + u32 width, height; + + if (!rect->width || !rect->height) + return; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + * */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - rect->dx; + height = y2 - rect->dy; + + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += rect->dy * par->next_line * 8 + rect->dx; + while (height--) { + switch (rect->rop) { + case ROP_COPY: + fill_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, width, + rect->color); + break; + + case ROP_XOR: + xor_one_line(info->var.bits_per_pixel, par->next_plane, + dst, dst_idx, width, rect->color); + break; + } + dst_idx += par->next_line * 8; + } +} + +static inline void copy_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG - 1); + bitcpy(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; + } +} + +static inline void copy_one_line_rev(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG - 1); + bitcpy_rev(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; + } +} + + +static void amifb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct amifb_par *par = info->par; + int x2, y2; + u32 dx, dy, sx, sy, width, height; + unsigned long *dst, *src; + int dst_idx, src_idx; + int rev_copy = 0; + + /* clip the destination */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + if (area->sx + dx < area->dx || area->sy + dy < area->dy) + return; + + /* update sx,sy */ + sx = area->sx + (dx - area->dx); + sy = area->sy + (dy - area->dy); + + /* the source must be completely inside the virtual screen */ + if (sx + width > info->var.xres_virtual || + sy + height > info->var.yres_virtual) + return; + + if (dy > sy || (dy == sy && dx > sx)) { + dy += height; + sy += height; + rev_copy = 1; + } + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + src = dst; + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + src_idx = dst_idx; + dst_idx += dy * par->next_line * 8 + dx; + src_idx += sy * par->next_line * 8 + sx; + if (rev_copy) { + while (height--) { + dst_idx -= par->next_line * 8; + src_idx -= par->next_line * 8; + copy_one_line_rev(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, width); + } + } else { + while (height--) { + copy_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, width); + dst_idx += par->next_line * 8; + src_idx += par->next_line * 8; + } + } +} + + +static inline void expand_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + const unsigned long *src; + int src_idx; + + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + if ((bgcolor ^ fgcolor) & 1) { + src = (unsigned long *) + ((unsigned long)data & ~(BYTES_PER_LONG - 1)); + src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; + if (fgcolor & 1) + bitcpy(dst, dst_idx, src, src_idx, n); + else + bitcpy_not(dst, dst_idx, src, src_idx, n); + /* set or clear */ + } else + bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); + if (!--bpp) + break; + bgcolor >>= 1; + fgcolor >>= 1; + dst_idx += next_plane * 8; + } +} + + +static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct amifb_par *par = info->par; + int x2, y2; + unsigned long *dst; + int dst_idx; + const char *src; + u32 dx, dy, width, height, pitch; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly like we are + * doing here. + */ + x2 = image->dx + image->width; + y2 = image->dy + image->height; + dx = image->dx; + dy = image->dy; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + if (image->depth == 1) { + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += dy * par->next_line * 8 + dx; + src = image->data; + pitch = (image->width + 7) / 8; + while (height--) { + expand_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, width, + src, image->bg_color, + image->fg_color); + dst_idx += par->next_line * 8; + src += pitch; + } + } else { + c2p_planar(info->screen_base, image->data, dx, dy, width, + height, par->next_line, par->next_plane, + image->width, info->var.bits_per_pixel); + } +} + + + /* + * Amiga Frame Buffer Specific ioctls + */ + +static int amifb_ioctl(struct fb_info *info, + unsigned int cmd, unsigned long arg) +{ + union { + struct fb_fix_cursorinfo fix; + struct fb_var_cursorinfo var; + struct fb_cursorstate state; + } crsr; + void __user *argp = (void __user *)arg; + int i; + + switch (cmd) { + case FBIOGET_FCURSORINFO: + i = ami_get_fix_cursorinfo(&crsr.fix, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.fix, + sizeof(crsr.fix)) ? -EFAULT : 0; + + case FBIOGET_VCURSORINFO: + i = ami_get_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.var, + sizeof(crsr.var)) ? -EFAULT : 0; + + case FBIOPUT_VCURSORINFO: + if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) + return -EFAULT; + return ami_set_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + + case FBIOGET_CURSORSTATE: + i = ami_get_cursorstate(&crsr.state, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.state, + sizeof(crsr.state)) ? -EFAULT : 0; + + case FBIOPUT_CURSORSTATE: + if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) + return -EFAULT; + return ami_set_cursorstate(&crsr.state, info->par); + } + return -EINVAL; +} + + + /* + * Flash the cursor (called by VBlank interrupt) + */ + +static int flash_cursor(void) +{ + static int cursorcount = 1; + + if (cursormode == FB_CURSOR_FLASH) { + if (!--cursorcount) { + cursorstate = -cursorstate; + cursorcount = cursorrate; + if (!is_blanked) + return 1; + } + } + return 0; +} + + /* + * VBlank Display Interrupt + */ + +static irqreturn_t amifb_interrupt(int irq, void *dev_id) +{ + struct amifb_par *par = dev_id; + + if (do_vmode_pan || do_vmode_full) + ami_update_display(par); + + if (do_vmode_full) + ami_init_display(par); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(par); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(par); + do_cursor = 0; + } else { + if (flash_cursor()) + ami_set_sprite(par); + } + + if (do_blank) { + ami_do_blank(par); + do_blank = 0; + } + + if (do_vmode_full) { + ami_reinit_copper(par); + do_vmode_full = 0; + } + return IRQ_HANDLED; +} + + +static const struct fb_ops amifb_ops = { + .owner = THIS_MODULE, + __FB_DEFAULT_IOMEM_OPS_RDWR, + .fb_check_var = amifb_check_var, + .fb_set_par = amifb_set_par, + .fb_setcolreg = amifb_setcolreg, + .fb_blank = amifb_blank, + .fb_pan_display = amifb_pan_display, + .fb_fillrect = amifb_fillrect, + .fb_copyarea = amifb_copyarea, + .fb_imageblit = amifb_imageblit, + .fb_ioctl = amifb_ioctl, + __FB_DEFAULT_IOMEM_OPS_MMAP, +}; + + + /* + * Allocate, Clear and Align a Block of Chip Memory + */ + +static void *aligned_chipptr; + +static inline u_long __init chipalloc(u_long size) +{ + aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]"); + if (!aligned_chipptr) { + pr_err("amifb: No Chip RAM for frame buffer"); + return 0; + } + memset(aligned_chipptr, 0, size); + return (u_long)aligned_chipptr; +} + +static inline void chipfree(void) +{ + if (aligned_chipptr) + amiga_chip_free(aligned_chipptr); +} + + + /* + * Initialisation + */ + +static int __init amifb_probe(struct platform_device *pdev) +{ + struct fb_info *info; + int tag, i, err = 0; + u_long chipptr; + u_int defmode; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("amifb", &option)) { + amifb_video_off(); + return -ENODEV; + } + amifb_setup(option); +#endif + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); + if (!info) + return -ENOMEM; + + strcpy(info->fix.id, "Amiga "); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.accel = FB_ACCEL_AMIGABLITT; + + switch (amiga_chipset) { +#ifdef CONFIG_FB_AMIGA_OCS + case CS_OCS: + strcat(info->fix.id, "OCS"); +default_chipset: + chipset = TAG_OCS; + maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; + info->fix.smem_len = VIDEOMEMSIZE_OCS; + break; +#endif /* CONFIG_FB_AMIGA_OCS */ + +#ifdef CONFIG_FB_AMIGA_ECS + case CS_ECS: + strcat(info->fix.id, "ECS"); + chipset = TAG_ECS; + maxdepth[TAG_SHRES] = 2; + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (AMIGAHW_PRESENT(AMBER_FF)) + defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL + : DEFMODE_AMBER_NTSC; + else + defmode = amiga_vblank == 50 ? DEFMODE_PAL + : DEFMODE_NTSC; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_2M) + info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; + break; +#endif /* CONFIG_FB_AMIGA_ECS */ + +#ifdef CONFIG_FB_AMIGA_AGA + case CS_AGA: + strcat(info->fix.id, "AGA"); + chipset = TAG_AGA; + maxdepth[TAG_SHRES] = 8; + maxdepth[TAG_HIRES] = 8; + maxdepth[TAG_LORES] = 8; + maxfmode = TAG_FMODE_4; + defmode = DEFMODE_AGA; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_2M) + info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; + break; +#endif /* CONFIG_FB_AMIGA_AGA */ + + default: +#ifdef CONFIG_FB_AMIGA_OCS + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(info->fix.id, "Unknown"); + goto default_chipset; +#else /* CONFIG_FB_AMIGA_OCS */ + err = -ENODEV; + goto release; +#endif /* CONFIG_FB_AMIGA_OCS */ + break; + } + + /* + * Calculate the Pixel Clock Values for this Machine + */ + + { + u_long tmp = DIVUL(200000000000ULL, amiga_eclock); + + pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */ + pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */ + pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */ + } + + /* + * Replace the Tag Values with the Real Pixel Clock Values + */ + + for (i = 0; i < NUM_TOTAL_MODES; i++) { + struct fb_videomode *mode = &ami_modedb[i]; + tag = mode->pixclock; + if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { + mode->pixclock = pixclock[tag]; + } + } + + if (amifb_hfmin) { + info->monspecs.hfmin = amifb_hfmin; + info->monspecs.hfmax = amifb_hfmax; + info->monspecs.vfmin = amifb_vfmin; + info->monspecs.vfmax = amifb_vfmax; + } else { + /* + * These are for a typical Amiga monitor (e.g. A1960) + */ + info->monspecs.hfmin = 15000; + info->monspecs.hfmax = 38000; + info->monspecs.vfmin = 49; + info->monspecs.vfmax = 90; + } + + info->fbops = &amifb_ops; + info->device = &pdev->dev; + + if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, + NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { + err = -EINVAL; + goto release; + } + + fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, + &info->modelist); + + round_down_bpp = 0; + chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + + DUMMYSPRITEMEMSIZE + COPINITSIZE + + 4 * COPLISTSIZE); + if (!chipptr) { + err = -ENOMEM; + goto release; + } + + assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); + assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); + assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); + assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); + assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); + + /* + * access the videomem with writethrough cache + */ + info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_wt(info->fix.smem_start, + info->fix.smem_len); + if (!videomemory) { + dev_warn(&pdev->dev, + "Unable to map videomem cached writethrough\n"); + info->screen_base = ZTWO_VADDR(info->fix.smem_start); + } else + info->screen_base = (char *)videomemory; + + memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); + + /* + * Make sure the Copper has something to do + */ + ami_init_copper(); + + /* + * Enable Display DMA + */ + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; + + err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, + "fb vertb handler", info->par); + if (err) + goto disable_dma; + + err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); + if (err) + goto free_irq; + + platform_set_drvdata(pdev, info); + + err = register_framebuffer(info); + if (err) + goto unset_drvdata; + + fb_info(info, "%s frame buffer device, using %dK of video memory\n", + info->fix.id, info->fix.smem_len>>10); + + return 0; + +unset_drvdata: + fb_dealloc_cmap(&info->cmap); +free_irq: + free_irq(IRQ_AMIGA_COPPER, info->par); +disable_dma: + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); +release: + framebuffer_release(info); + return err; +} + + +static void __exit amifb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + free_irq(IRQ_AMIGA_COPPER, info->par); + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); + framebuffer_release(info); + amifb_video_off(); +} + +/* + * amifb_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this ok because they cannot get unboud at + * runtime. The driver needs to be marked with __refdata, otherwise modpost + * triggers a section mismatch warning. + */ +static struct platform_driver amifb_driver __refdata = { + .remove = __exit_p(amifb_remove), + .driver = { + .name = "amiga-video", + }, +}; + +module_platform_driver_probe(amifb_driver, amifb_probe); + +MODULE_DESCRIPTION("Amiga builtin chipset frame buffer driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:amiga-video"); diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c new file mode 100644 index 000000000..b807cf075 --- /dev/null +++ b/drivers/video/fbdev/arcfb.c @@ -0,0 +1,616 @@ +/* + * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board + * + * Copyright (C) 2005, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This driver was written to be used with the Arc LCD board. Arc uses a + * set of KS108 chips that control individual 64x64 LCD matrices. The board + * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and + * so on. The interface between the board and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 4+n lines for control. On a + * GPIO-less system, the board can be tested by connecting the respective sigs + * up to a parallel port connector. The driver requires the IO addresses for + * data and control GPIO at load time. It is unable to probe for the + * existence of the LCD so it must be told at load time whether it should + * be enabled or not. + * + * Todo: + * - testing with 4x4 + * - testing with interrupt hw + * + * General notes: + * - User must set tuhold. It's in microseconds. According to the 108 spec, + * the hold time is supposed to be at least 1 microsecond. + * - User must set num_cols=x num_rows=y, eg: x=2 means 128 + * - User must set arcfb_enable=1 to enable it + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define floor8(a) (a&(~0x07)) +#define floorXres(a,xres) (a&(~(xres - 1))) +#define iceil8(a) (((int)((a+7)/8))*8) +#define ceil64(a) (a|0x3F) +#define ceilXres(a,xres) (a|(xres - 1)) + +/* ks108 chipset specific defines and code */ + +#define KS_SET_DPY_START_LINE 0xC0 +#define KS_SET_PAGE_NUM 0xB8 +#define KS_SET_X 0x40 +#define KS_CEHI 0x01 +#define KS_CELO 0x00 +#define KS_SEL_CMD 0x08 +#define KS_SEL_DATA 0x00 +#define KS_DPY_ON 0x3F +#define KS_DPY_OFF 0x3E +#define KS_INTACK 0x40 +#define KS_CLRINT 0x02 + +struct arcfb_par { + unsigned long dio_addr; + unsigned long cio_addr; + unsigned long c2io_addr; + atomic_t ref_count; + unsigned char cslut[9]; + struct fb_info *info; + unsigned int irq; + spinlock_t lock; +}; + +static const struct fb_fix_screeninfo arcfb_fix = { + .id = "arcfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO01, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static const struct fb_var_screeninfo arcfb_var = { + .xres = 128, + .yres = 64, + .xres_virtual = 128, + .yres_virtual = 64, + .bits_per_pixel = 1, + .nonstd = 1, +}; + +static unsigned long num_cols; +static unsigned long num_rows; +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned long tuhold; +static unsigned int nosplash; +static unsigned int arcfb_enable; +static unsigned int irq; + +static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq); + +static void ks108_writeb_ctl(struct arcfb_par *par, + unsigned int chipindex, unsigned char value) +{ + unsigned char chipselval = par->cslut[chipindex]; + + outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr); + outb(value, par->dio_addr); + udelay(tuhold); + outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr); +} + +static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value) +{ + + outb(value, par->cio_addr); + udelay(tuhold); +} + +static unsigned char ks108_readb_ctl2(struct arcfb_par *par) +{ + return inb(par->c2io_addr); +} + +static void ks108_writeb_data(struct arcfb_par *par, + unsigned int chipindex, unsigned char value) +{ + unsigned char chipselval = par->cslut[chipindex]; + + outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr); + outb(value, par->dio_addr); + udelay(tuhold); + outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr); +} + +static void ks108_set_start_line(struct arcfb_par *par, + unsigned int chipindex, unsigned char y) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y); +} + +static void ks108_set_yaddr(struct arcfb_par *par, + unsigned int chipindex, unsigned char y) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y); +} + +static void ks108_set_xaddr(struct arcfb_par *par, + unsigned int chipindex, unsigned char x) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_X|x); +} + +static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex) +{ + int i,j; + + for (i = 0; i <= 8; i++) { + ks108_set_yaddr(par, chipindex, i); + ks108_set_xaddr(par, chipindex, 0); + for (j = 0; j < 64; j++) { + ks108_writeb_data(par, chipindex, + (unsigned char) splashval); + } + } +} + +/* main arcfb functions */ + +static int arcfb_open(struct fb_info *info, int user) +{ + struct arcfb_par *par = info->par; + + atomic_inc(&par->ref_count); + return 0; +} + +static int arcfb_release(struct fb_info *info, int user) +{ + struct arcfb_par *par = info->par; + int count = atomic_read(&par->ref_count); + + if (!count) + return -EINVAL; + atomic_dec(&par->ref_count); + return 0; +} + +static int arcfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int i; + struct arcfb_par *par = info->par; + + if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64) + && (info->var.yres <= 64)) { + for (i = 0; i < num_cols; i++) { + ks108_set_start_line(par, i, var->yoffset); + } + info->var.yoffset = var->yoffset; + return 0; + } + + return -EINVAL; +} + +static irqreturn_t arcfb_interrupt(int vec, void *dev_instance) +{ + struct fb_info *info = dev_instance; + unsigned char ctl2status; + struct arcfb_par *par = info->par; + + ctl2status = ks108_readb_ctl2(par); + + if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */ + return IRQ_NONE; + + ks108_writeb_mainctl(par, KS_CLRINT); + + spin_lock(&par->lock); + if (waitqueue_active(&arcfb_waitq)) { + wake_up(&arcfb_waitq); + } + spin_unlock(&par->lock); + + return IRQ_HANDLED; +} + +/* + * here we handle a specific page on the lcd. the complexity comes from + * the fact that the fb is laidout in 8xX vertical columns. we extract + * each write of 8 vertical pixels. then we shift out as we move along + * X. That's what rightshift does. bitmask selects the desired input bit. + */ +static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper, + unsigned int left, unsigned int right, unsigned int distance) +{ + unsigned char *src; + unsigned int xindex, yindex, chipindex, linesize; + int i; + unsigned char val; + unsigned char bitmask, rightshift; + + xindex = left >> 6; + yindex = upper >> 6; + chipindex = (xindex + (yindex*num_cols)); + + ks108_set_yaddr(par, chipindex, upper/8); + + linesize = par->info->var.xres/8; + src = (unsigned char *)par->info->screen_buffer + (left/8) + + (upper * linesize); + ks108_set_xaddr(par, chipindex, left); + + bitmask=1; + rightshift=0; + while (left <= right) { + val = 0; + for (i = 0; i < 8; i++) { + if ( i > rightshift) { + val |= (*(src + (i*linesize)) & bitmask) + << (i - rightshift); + } else { + val |= (*(src + (i*linesize)) & bitmask) + >> (rightshift - i); + } + } + ks108_writeb_data(par, chipindex, val); + left++; + if (bitmask == 0x80) { + bitmask = 1; + src++; + rightshift=0; + } else { + bitmask <<= 1; + rightshift++; + } + } +} + +/* + * here we handle the entire vertical page of the update. we write across + * lcd chips. update_page uses the upper/left values to decide which + * chip to select for the right. upper is needed for setting the page + * desired for the write. + */ +static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top, + unsigned int bottom, unsigned int left, unsigned int right) +{ + unsigned int distance, upper, lower; + + distance = (bottom - top) + 1; + upper = top; + lower = top + 7; + + while (distance > 0) { + distance -= 8; + arcfb_lcd_update_page(par, upper, left, right, 8); + upper = lower + 1; + lower = upper + 7; + } +} + +/* + * here we handle horizontal blocks for the update. update_vert will + * handle spaning multiple pages. we break out each horizontal + * block in to individual blocks no taller than 64 pixels. + */ +static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left, + unsigned int right, unsigned int top, unsigned int h) +{ + unsigned int distance, upper, lower; + + distance = h; + upper = floor8(top); + lower = min(upper + distance - 1, ceil64(upper)); + + while (distance > 0) { + distance -= ((lower - upper) + 1 ); + arcfb_lcd_update_vert(par, upper, lower, left, right); + upper = lower + 1; + lower = min(upper + distance - 1, ceil64(upper)); + } +} + +/* + * here we start the process of splitting out the fb update into + * individual blocks of pixels. we end up splitting into 64x64 blocks + * and finally down to 64x8 pages. + */ +static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx, + unsigned int dy, unsigned int w, unsigned int h) +{ + unsigned int left, right, distance, y; + + /* align the request first */ + y = floor8(dy); + h += dy - y; + h = iceil8(h); + + distance = w; + left = dx; + right = min(left + w - 1, ceil64(left)); + + while (distance > 0) { + arcfb_lcd_update_horiz(par, left, right, y, h); + distance -= ((right - left) + 1); + left = right + 1; + right = min(left + distance - 1, ceil64(left)); + } +} + +static int arcfb_ioctl(struct fb_info *info, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct arcfb_par *par = info->par; + unsigned long flags; + + switch (cmd) { + case FBIO_WAITEVENT: + { + DEFINE_WAIT(wait); + /* illegal to wait on arc if no irq will occur */ + if (!par->irq) + return -EINVAL; + + /* wait until the Arc has generated an interrupt + * which will wake us up */ + spin_lock_irqsave(&par->lock, flags); + prepare_to_wait(&arcfb_waitq, &wait, + TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&par->lock, flags); + schedule(); + finish_wait(&arcfb_waitq, &wait); + } + fallthrough; + + case FBIO_GETCONTROL2: + { + unsigned char ctl2; + + ctl2 = ks108_readb_ctl2(info->par); + if (copy_to_user(argp, &ctl2, sizeof(ctl2))) + return -EFAULT; + return 0; + } + default: + return -EINVAL; + } +} + +static void arcfb_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct arcfb_par *par = info->par; + unsigned int xres = info->var.xres; + unsigned int bitppos, startpos, endpos, bitcount; + unsigned int x, y, width, height; + + bitppos = off * 8; + startpos = floorXres(bitppos, xres); + endpos = ceilXres((bitppos + (len * 8)), xres); + bitcount = endpos - startpos; + + x = startpos % xres; + y = startpos / xres; + width = xres; + height = bitcount / xres; + + arcfb_lcd_update(par, x, y, width, height); +} + +static void arcfb_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) +{ + struct arcfb_par *par = info->par; + + /* update the physical lcd */ + arcfb_lcd_update(par, x, y, width, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(arcfb, + arcfb_damage_range, + arcfb_damage_area) + +static const struct fb_ops arcfb_ops = { + .owner = THIS_MODULE, + .fb_open = arcfb_open, + __FB_DEFAULT_DEFERRED_OPS_RDWR(arcfb), + .fb_release = arcfb_release, + .fb_pan_display = arcfb_pan_display, + __FB_DEFAULT_DEFERRED_OPS_DRAW(arcfb), + .fb_ioctl = arcfb_ioctl, + // .fb_mmap reqires deferred I/O +}; + +static int arcfb_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + int videomemorysize; + unsigned char *videomemory; + struct arcfb_par *par; + int i; + + videomemorysize = (((64*64)*num_cols)*num_rows)/8; + + /* We need a flat backing store for the Arc's + less-flat actual paged framebuffer */ + videomemory = vzalloc(videomemorysize); + if (!videomemory) + return retval; + + info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev); + if (!info) + goto err_fb_alloc; + + info->flags |= FBINFO_VIRTFB; + info->screen_buffer = videomemory; + info->fbops = &arcfb_ops; + + info->var = arcfb_var; + info->fix = arcfb_fix; + par = info->par; + par->info = info; + + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + goto err_addr; + } + par->dio_addr = dio_addr; + par->cio_addr = cio_addr; + par->c2io_addr = c2io_addr; + par->cslut[0] = 0x00; + par->cslut[1] = 0x06; + spin_lock_init(&par->lock); + if (irq) { + par->irq = irq; + if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED, + "arcfb", info)) { + printk(KERN_INFO + "arcfb: Failed req IRQ %d\n", par->irq); + retval = -EBUSY; + goto err_addr; + } + } + retval = register_framebuffer(info); + if (retval < 0) + goto err_register_fb; + platform_set_drvdata(dev, info); + fb_info(info, "Arc frame buffer device, using %dK of video memory\n", + videomemorysize >> 10); + + /* this inits the lcd but doesn't clear dirty pixels */ + for (i = 0; i < num_cols * num_rows; i++) { + ks108_writeb_ctl(par, i, KS_DPY_OFF); + ks108_set_start_line(par, i, 0); + ks108_set_yaddr(par, i, 0); + ks108_set_xaddr(par, i, 0); + ks108_writeb_ctl(par, i, KS_DPY_ON); + } + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + for (i = 0; i < num_cols * num_rows; i++) { + fb_info(info, "splashing lcd %d\n", i); + ks108_set_start_line(par, i, 0); + ks108_clear_lcd(par, i); + } + } + + return 0; + +err_register_fb: + free_irq(par->irq, info); +err_addr: + framebuffer_release(info); +err_fb_alloc: + vfree(videomemory); + return retval; +} + +static void arcfb_remove(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + + if (info) { + unregister_framebuffer(info); + if (irq) + free_irq(((struct arcfb_par *)(info->par))->irq, info); + vfree(info->screen_buffer); + framebuffer_release(info); + } +} + +static struct platform_driver arcfb_driver = { + .probe = arcfb_probe, + .remove = arcfb_remove, + .driver = { + .name = "arcfb", + }, +}; + +static struct platform_device *arcfb_device; + +static int __init arcfb_init(void) +{ + int ret; + + if (!arcfb_enable) + return -ENXIO; + + ret = platform_driver_register(&arcfb_driver); + if (!ret) { + arcfb_device = platform_device_alloc("arcfb", 0); + if (arcfb_device) { + ret = platform_device_add(arcfb_device); + } else { + ret = -ENOMEM; + } + if (ret) { + platform_device_put(arcfb_device); + platform_driver_unregister(&arcfb_driver); + } + } + return ret; + +} + +static void __exit arcfb_exit(void) +{ + platform_device_unregister(arcfb_device); + platform_driver_unregister(&arcfb_driver); +} + +module_param(num_cols, ulong, 0); +MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide"); +module_param(num_rows, ulong, 0); +MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high"); +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(arcfb_enable, uint, 0); +MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board"); +module_param_hw(dio_addr, ulong, ioport, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param_hw(cio_addr, ulong, ioport, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param_hw(c2io_addr, ulong, ioport, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green"); +module_param(tuhold, ulong, 0); +MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board"); +module_param_hw(irq, uint, irq, 0); +MODULE_PARM_DESC(irq, "IRQ for the Arc board"); + +module_init(arcfb_init); +module_exit(arcfb_exit); + +MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c new file mode 100644 index 000000000..195dbf4a5 --- /dev/null +++ b/drivers/video/fbdev/arkfb.c @@ -0,0 +1,1218 @@ +/* + * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV + * with ICS 5342 dac (it is easy to add support for different dacs). + * + * Copyright (c) 2007 Ondrej Zajicek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Code is based on s3fb + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Why should fb driver call console functions? because console_lock() */ +#include