Commit | Line | Data |
---|---|---|
fc4effc7 DV |
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 "geodefb.h" | |
22 | #include "display_gx.h" | |
23 | ||
f378819a JC |
24 | #ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE |
25 | unsigned int gx_frame_buffer_size(void) | |
26 | { | |
27 | return CONFIG_FB_GEODE_GX_FBSIZE; | |
28 | } | |
29 | #else | |
4c1979c8 | 30 | unsigned int gx_frame_buffer_size(void) |
fc4effc7 | 31 | { |
4c1979c8 JC |
32 | unsigned int val; |
33 | ||
34 | /* FB size is reported by a virtual register */ | |
35 | /* Virtual register class = 0x02 */ | |
36 | /* VG_MEM_SIZE(512Kb units) = 0x00 */ | |
37 | ||
38 | outw(0xFC53, 0xAC1C); | |
39 | outw(0x0200, 0xAC1C); | |
40 | ||
41 | val = (unsigned int)(inw(0xAC1E)) & 0xFFl; | |
42 | return (val << 19); | |
fc4effc7 | 43 | } |
f378819a | 44 | #endif |
fc4effc7 DV |
45 | |
46 | int gx_line_delta(int xres, int bpp) | |
47 | { | |
48 | /* Must be a multiple of 8 bytes. */ | |
49 | return (xres * (bpp >> 3) + 7) & ~0x7; | |
50 | } | |
51 | ||
52 | static void gx_set_mode(struct fb_info *info) | |
53 | { | |
54 | struct geodefb_par *par = info->par; | |
55 | u32 gcfg, dcfg; | |
56 | int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; | |
57 | int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; | |
58 | ||
59 | /* Unlock the display controller registers. */ | |
60 | readl(par->dc_regs + DC_UNLOCK); | |
61 | writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); | |
62 | ||
63 | gcfg = readl(par->dc_regs + DC_GENERAL_CFG); | |
64 | dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); | |
65 | ||
66 | /* Disable the timing generator. */ | |
67 | dcfg &= ~(DC_DCFG_TGEN); | |
68 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | |
69 | ||
70 | /* Wait for pending memory requests before disabling the FIFO load. */ | |
71 | udelay(100); | |
72 | ||
73 | /* Disable FIFO load and compression. */ | |
74 | gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); | |
75 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | |
76 | ||
77 | /* Setup DCLK and its divisor. */ | |
78 | par->vid_ops->set_dclk(info); | |
79 | ||
80 | /* | |
81 | * Setup new mode. | |
82 | */ | |
83 | ||
84 | /* Clear all unused feature bits. */ | |
85 | gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; | |
86 | dcfg = 0; | |
87 | ||
88 | /* Set FIFO priority (default 6/5) and enable. */ | |
89 | /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ | |
90 | gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; | |
91 | ||
92 | /* Framebuffer start offset. */ | |
93 | writel(0, par->dc_regs + DC_FB_ST_OFFSET); | |
94 | ||
95 | /* Line delta and line buffer length. */ | |
96 | writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); | |
97 | writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, | |
98 | par->dc_regs + DC_LINE_SIZE); | |
99 | ||
f378819a | 100 | |
fc4effc7 DV |
101 | /* Enable graphics and video data and unmask address lines. */ |
102 | dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; | |
103 | ||
104 | /* Set pixel format. */ | |
105 | switch (info->var.bits_per_pixel) { | |
106 | case 8: | |
107 | dcfg |= DC_DCFG_DISP_MODE_8BPP; | |
108 | break; | |
109 | case 16: | |
110 | dcfg |= DC_DCFG_DISP_MODE_16BPP; | |
111 | dcfg |= DC_DCFG_16BPP_MODE_565; | |
112 | break; | |
113 | case 32: | |
114 | dcfg |= DC_DCFG_DISP_MODE_24BPP; | |
115 | dcfg |= DC_DCFG_PALB; | |
116 | break; | |
117 | } | |
118 | ||
119 | /* Enable timing generator. */ | |
120 | dcfg |= DC_DCFG_TGEN; | |
121 | ||
122 | /* Horizontal and vertical timings. */ | |
123 | hactive = info->var.xres; | |
124 | hblankstart = hactive; | |
125 | hsyncstart = hblankstart + info->var.right_margin; | |
126 | hsyncend = hsyncstart + info->var.hsync_len; | |
127 | hblankend = hsyncend + info->var.left_margin; | |
128 | htotal = hblankend; | |
129 | ||
130 | vactive = info->var.yres; | |
131 | vblankstart = vactive; | |
132 | vsyncstart = vblankstart + info->var.lower_margin; | |
133 | vsyncend = vsyncstart + info->var.vsync_len; | |
134 | vblankend = vsyncend + info->var.upper_margin; | |
135 | vtotal = vblankend; | |
136 | ||
137 | writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); | |
138 | writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); | |
139 | writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); | |
140 | ||
141 | writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); | |
142 | writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); | |
143 | writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); | |
144 | ||
145 | /* Write final register values. */ | |
146 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | |
147 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | |
148 | ||
149 | par->vid_ops->configure_display(info); | |
150 | ||
151 | /* Relock display controller registers */ | |
152 | writel(0, par->dc_regs + DC_UNLOCK); | |
153 | } | |
154 | ||
155 | static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, | |
156 | unsigned red, unsigned green, unsigned blue) | |
157 | { | |
158 | struct geodefb_par *par = info->par; | |
159 | int val; | |
160 | ||
161 | /* Hardware palette is in RGB 8-8-8 format. */ | |
162 | val = (red << 8) & 0xff0000; | |
163 | val |= (green) & 0x00ff00; | |
164 | val |= (blue >> 8) & 0x0000ff; | |
165 | ||
166 | writel(regno, par->dc_regs + DC_PAL_ADDRESS); | |
167 | writel(val, par->dc_regs + DC_PAL_DATA); | |
168 | } | |
169 | ||
170 | struct geode_dc_ops gx_dc_ops = { | |
171 | .set_mode = gx_set_mode, | |
172 | .set_palette_reg = gx_set_hw_palette_reg, | |
173 | }; |