]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/video/geode/display_gx.c
3743c8766a08b8c0df5a5962e49813d22bd7804a
[net-next-2.6.git] / drivers / video / geode / display_gx.c
1 /*
2  * Geode GX display controller.
3  *
4  *   Copyright (C) 2005 Arcom Control Systems Ltd.
5  *
6  *   Portions from AMD's original 2.4 driver:
7  *     Copyright (C) 2004 Advanced Micro Devices, Inc.
8  *
9  *   This program is free software; you can redistribute it and/or modify it
10  *   under the terms of the GNU General Public License as published by * the
11  *   Free Software Foundation; either version 2 of the License, or * (at your
12  *   option) any later version.
13  */
14 #include <linux/spinlock.h>
15 #include <linux/fb.h>
16 #include <linux/delay.h>
17 #include <asm/io.h>
18 #include <asm/div64.h>
19 #include <asm/delay.h>
20
21 #include "gxfb.h"
22
23 unsigned int gx_frame_buffer_size(void)
24 {
25         unsigned int val;
26
27         /* FB size is reported by a virtual register */
28         /* Virtual register class = 0x02 */
29         /* VG_MEM_SIZE(512Kb units) = 0x00 */
30
31         outw(0xFC53, 0xAC1C);
32         outw(0x0200, 0xAC1C);
33
34         val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
35         return (val << 19);
36 }
37
38 int gx_line_delta(int xres, int bpp)
39 {
40         /* Must be a multiple of 8 bytes. */
41         return (xres * (bpp >> 3) + 7) & ~0x7;
42 }
43
44 void gx_set_mode(struct fb_info *info)
45 {
46         struct gxfb_par *par = info->par;
47         u32 gcfg, dcfg;
48         int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
49         int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
50
51         /* Unlock the display controller registers. */
52         write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
53
54         gcfg = read_dc(par, DC_GENERAL_CFG);
55         dcfg = read_dc(par, DC_DISPLAY_CFG);
56
57         /* Disable the timing generator. */
58         dcfg &= ~DC_DISPLAY_CFG_TGEN;
59         write_dc(par, DC_DISPLAY_CFG, dcfg);
60
61         /* Wait for pending memory requests before disabling the FIFO load. */
62         udelay(100);
63
64         /* Disable FIFO load and compression. */
65         gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE |
66                         DC_GENERAL_CFG_DECE);
67         write_dc(par, DC_GENERAL_CFG, gcfg);
68
69         /* Setup DCLK and its divisor. */
70         gx_set_dclk_frequency(info);
71
72         /*
73          * Setup new mode.
74          */
75
76         /* Clear all unused feature bits. */
77         gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE;
78         dcfg = 0;
79
80         /* Set FIFO priority (default 6/5) and enable. */
81         /* FIXME: increase fifo priority for 1280x1024 and higher modes? */
82         gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) |
83                 (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE;
84
85         /* Framebuffer start offset. */
86         write_dc(par, DC_FB_ST_OFFSET, 0);
87
88         /* Line delta and line buffer length. */
89         write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
90         write_dc(par, DC_LINE_SIZE,
91                 ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2);
92
93
94         /* Enable graphics and video data and unmask address lines. */
95         dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN |
96                 DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M;
97
98         /* Set pixel format. */
99         switch (info->var.bits_per_pixel) {
100         case 8:
101                 dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP;
102                 break;
103         case 16:
104                 dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP;
105                 break;
106         case 32:
107                 dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP;
108                 dcfg |= DC_DISPLAY_CFG_PALB;
109                 break;
110         }
111
112         /* Enable timing generator. */
113         dcfg |= DC_DISPLAY_CFG_TGEN;
114
115         /* Horizontal and vertical timings. */
116         hactive = info->var.xres;
117         hblankstart = hactive;
118         hsyncstart = hblankstart + info->var.right_margin;
119         hsyncend =  hsyncstart + info->var.hsync_len;
120         hblankend = hsyncend + info->var.left_margin;
121         htotal = hblankend;
122
123         vactive = info->var.yres;
124         vblankstart = vactive;
125         vsyncstart = vblankstart + info->var.lower_margin;
126         vsyncend =  vsyncstart + info->var.vsync_len;
127         vblankend = vsyncend + info->var.upper_margin;
128         vtotal = vblankend;
129
130         write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1)    |
131                         ((htotal - 1) << 16));
132         write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) |
133                         ((hblankend - 1) << 16));
134         write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1)   |
135                         ((hsyncend - 1) << 16));
136
137         write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1)    |
138                         ((vtotal - 1) << 16));
139         write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) |
140                         ((vblankend - 1) << 16));
141         write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1)   |
142                         ((vsyncend - 1) << 16));
143
144         /* Write final register values. */
145         write_dc(par, DC_DISPLAY_CFG, dcfg);
146         write_dc(par, DC_GENERAL_CFG, gcfg);
147
148         gx_configure_display(info);
149
150         /* Relock display controller registers */
151         write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
152 }
153
154 void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
155                 unsigned red, unsigned green, unsigned blue)
156 {
157         struct gxfb_par *par = info->par;
158         int val;
159
160         /* Hardware palette is in RGB 8-8-8 format. */
161         val  = (red   << 8) & 0xff0000;
162         val |= (green)      & 0x00ff00;
163         val |= (blue  >> 8) & 0x0000ff;
164
165         write_dc(par, DC_PAL_ADDRESS, regno);
166         write_dc(par, DC_PAL_DATA, val);
167 }