]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * drivers/video/tx3912fb.c | |
3 | * | |
4 | * Copyright (C) 1999 Harald Koerfgen | |
5 | * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com) | |
6 | * | |
7 | * This file is subject to the terms and conditions of the GNU General Public | |
8 | * License. See the file COPYING in the main directory of this archive for | |
9 | * more details. | |
10 | * | |
11 | * Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors | |
12 | */ | |
13 | #include <linux/module.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/string.h> | |
17 | #include <linux/tty.h> | |
18 | #include <linux/delay.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/pm.h> | |
22 | #include <linux/fb.h> | |
23 | #include <asm/io.h> | |
24 | #include <asm/bootinfo.h> | |
25 | #include <asm/uaccess.h> | |
26 | #include <asm/tx3912.h> | |
27 | #include <video/tx3912.h> | |
28 | ||
29 | /* | |
30 | * Frame buffer, palette and console structures | |
31 | */ | |
32 | static struct fb_info fb_info; | |
33 | static u32 cfb8[16]; | |
34 | ||
35 | static struct fb_fix_screeninfo tx3912fb_fix __initdata = { | |
36 | .id = "tx3912fb", | |
37 | .smem_len = ((240 * 320)/2), | |
38 | .type = FB_TYPE_PACKED_PIXELS, | |
39 | .visual = FB_VISUAL_TRUECOLOR, | |
40 | .xpanstep = 1, | |
41 | .ypanstep = 1, | |
42 | .ywrapstep = 1, | |
43 | .accel = FB_ACCEL_NONE, | |
44 | }; | |
45 | ||
46 | static struct fb_var_screeninfo tx3912fb_var = { | |
47 | .xres = 240, | |
48 | .yres = 320, | |
49 | .xres_virtual = 240, | |
50 | .yres_virtual = 320, | |
51 | .bits_per_pixel =4, | |
52 | .red = { 0, 4, 0 }, /* ??? */ | |
53 | .green = { 0, 4, 0 }, | |
54 | .blue = { 0, 4, 0 }, | |
55 | .activate = FB_ACTIVATE_NOW, | |
56 | .width = -1, | |
57 | .height = -1, | |
58 | .pixclock = 20000, | |
59 | .left_margin = 64, | |
60 | .right_margin = 64, | |
61 | .upper_margin = 32, | |
62 | .lower_margin = 32, | |
63 | .hsync_len = 64, | |
64 | .vsync_len = 2, | |
65 | .vmode = FB_VMODE_NONINTERLACED, | |
66 | }; | |
67 | ||
68 | /* | |
69 | * Interface used by the world | |
70 | */ | |
71 | int tx3912fb_init(void); | |
72 | ||
73 | static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, | |
74 | u_int blue, u_int transp, | |
75 | struct fb_info *info); | |
76 | ||
77 | /* | |
78 | * Macros | |
79 | */ | |
80 | #define get_line_length(xres_virtual, bpp) \ | |
81 | (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3) | |
82 | ||
83 | /* | |
84 | * Frame buffer operations structure used by console driver | |
85 | */ | |
86 | static struct fb_ops tx3912fb_ops = { | |
87 | .owner = THIS_MODULE, | |
88 | .fb_setcolreg = tx3912fb_setcolreg, | |
89 | .fb_fillrect = cfb_fillrect, | |
90 | .fb_copyarea = cfb_copyarea, | |
91 | .fb_imageblit = cfb_imageblit, | |
92 | .fb_cursor = soft_cursor, | |
93 | }; | |
94 | ||
95 | static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |
96 | { | |
97 | /* | |
98 | * Memory limit | |
99 | */ | |
100 | line_length = | |
101 | get_line_length(var->xres_virtual, var->bits_per_pixel); | |
102 | if ((line_length * var->yres_virtual) > info->fix.smem_len) | |
103 | return -ENOMEM; | |
104 | ||
105 | return 0; | |
106 | } | |
107 | ||
108 | static int tx3912fb_set_par(struct fb_info *info) | |
109 | { | |
110 | u_long tx3912fb_paddr = 0; | |
111 | ||
112 | /* Disable the video logic */ | |
113 | outl(inl(TX3912_VIDEO_CTRL1) & | |
114 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
115 | TX3912_VIDEO_CTRL1); | |
116 | udelay(200); | |
117 | ||
118 | /* Set start address for DMA transfer */ | |
119 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | |
120 | ||
121 | /* Set end address for DMA transfer */ | |
122 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | |
123 | ||
124 | /* Set the pixel depth */ | |
125 | switch (info->var.bits_per_pixel) { | |
126 | case 1: | |
127 | /* Monochrome */ | |
128 | outl(inl(TX3912_VIDEO_CTRL1) & | |
129 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
130 | info->fix.visual = FB_VISUAL_MONO10; | |
131 | break; | |
132 | case 4: | |
133 | /* 4-bit gray */ | |
134 | outl(inl(TX3912_VIDEO_CTRL1) & | |
135 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
136 | outl(inl(TX3912_VIDEO_CTRL1) | | |
137 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | |
138 | TX3912_VIDEO_CTRL1); | |
139 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
140 | break; | |
141 | case 8: | |
142 | /* 8-bit color */ | |
143 | outl(inl(TX3912_VIDEO_CTRL1) & | |
144 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
145 | outl(inl(TX3912_VIDEO_CTRL1) | | |
146 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | |
147 | TX3912_VIDEO_CTRL1); | |
148 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
149 | break; | |
150 | case 2: | |
151 | default: | |
152 | /* 2-bit gray */ | |
153 | outl(inl(TX3912_VIDEO_CTRL1) & | |
154 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
155 | outl(inl(TX3912_VIDEO_CTRL1) | | |
156 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | |
157 | TX3912_VIDEO_CTRL1); | |
158 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | |
159 | break; | |
160 | } | |
161 | ||
162 | /* Enable the video clock */ | |
163 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | |
164 | TX3912_CLK_CTRL); | |
165 | ||
166 | /* Unfreeze video logic and enable DF toggle */ | |
167 | outl(inl(TX3912_VIDEO_CTRL1) & | |
168 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | | |
169 | TX3912_VIDEO_CTRL1_DFMODE) | |
170 | , TX3912_VIDEO_CTRL1); | |
171 | udelay(200); | |
172 | ||
173 | /* Enable the video logic */ | |
174 | outl(inl(TX3912_VIDEO_CTRL1) | | |
175 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
176 | TX3912_VIDEO_CTRL1); | |
177 | ||
178 | info->fix.line_length = get_line_length(var->xres_virtual, | |
179 | var->bits_per_pixel); | |
180 | } | |
181 | ||
182 | /* | |
183 | * Set a single color register | |
184 | */ | |
185 | static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, | |
186 | u_int blue, u_int transp, | |
187 | struct fb_info *info) | |
188 | { | |
189 | if (regno > 255) | |
190 | return 1; | |
191 | ||
192 | if (regno < 16) | |
193 | ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8) | |
194 | | ((green & 0xe000) >> 11) | |
195 | | ((blue & 0xc000) >> 14); | |
196 | return 0; | |
197 | } | |
198 | ||
199 | int __init tx3912fb_setup(char *options); | |
200 | ||
201 | /* | |
202 | * Initialization of the framebuffer | |
203 | */ | |
204 | int __init tx3912fb_init(void) | |
205 | { | |
206 | u_long tx3912fb_paddr = 0; | |
207 | int size = (info->var.bits_per_pixel == 8) ? 256 : 16; | |
208 | char *option = NULL; | |
209 | ||
210 | if (fb_get_options("tx3912fb", &option)) | |
211 | return -ENODEV; | |
212 | tx3912fb_setup(option); | |
213 | ||
214 | /* Disable the video logic */ | |
215 | outl(inl(TX3912_VIDEO_CTRL1) & | |
216 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
217 | TX3912_VIDEO_CTRL1); | |
218 | udelay(200); | |
219 | ||
220 | /* Set start address for DMA transfer */ | |
221 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | |
222 | ||
223 | /* Set end address for DMA transfer */ | |
224 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | |
225 | ||
226 | /* Set the pixel depth */ | |
227 | switch (tx3912fb_var.bits_per_pixel) { | |
228 | case 1: | |
229 | /* Monochrome */ | |
230 | outl(inl(TX3912_VIDEO_CTRL1) & | |
231 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
232 | tx3912fb_fix.visual = FB_VISUAL_MONO10; | |
233 | break; | |
234 | case 4: | |
235 | /* 4-bit gray */ | |
236 | outl(inl(TX3912_VIDEO_CTRL1) & | |
237 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
238 | outl(inl(TX3912_VIDEO_CTRL1) | | |
239 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | |
240 | TX3912_VIDEO_CTRL1); | |
241 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | |
242 | tx3912fb_fix.grayscale = 1; | |
243 | break; | |
244 | case 8: | |
245 | /* 8-bit color */ | |
246 | outl(inl(TX3912_VIDEO_CTRL1) & | |
247 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
248 | outl(inl(TX3912_VIDEO_CTRL1) | | |
249 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | |
250 | TX3912_VIDEO_CTRL1); | |
251 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | |
252 | break; | |
253 | case 2: | |
254 | default: | |
255 | /* 2-bit gray */ | |
256 | outl(inl(TX3912_VIDEO_CTRL1) & | |
257 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
258 | outl(inl(TX3912_VIDEO_CTRL1) | | |
259 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | |
260 | TX3912_VIDEO_CTRL1); | |
261 | tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; | |
262 | tx3912fb_fix.grayscale = 1; | |
263 | break; | |
264 | } | |
265 | ||
266 | /* Enable the video clock */ | |
267 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | |
268 | TX3912_CLK_CTRL); | |
269 | ||
270 | /* Unfreeze video logic and enable DF toggle */ | |
271 | outl(inl(TX3912_VIDEO_CTRL1) & | |
272 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE), | |
273 | TX3912_VIDEO_CTRL1); | |
274 | udelay(200); | |
275 | ||
276 | /* Clear the framebuffer */ | |
277 | memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len); | |
278 | udelay(200); | |
279 | ||
280 | /* Enable the video logic */ | |
281 | outl(inl(TX3912_VIDEO_CTRL1) | | |
282 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
283 | TX3912_VIDEO_CTRL1); | |
284 | ||
285 | /* | |
286 | * Memory limit | |
287 | */ | |
288 | tx3912fb_fix.line_length = | |
289 | get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel); | |
290 | if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len) | |
291 | return -ENOMEM; | |
292 | ||
293 | fb_info.fbops = &tx3912fb_ops; | |
294 | fb_info.var = tx3912fb_var; | |
295 | fb_info.fix = tx3912fb_fix; | |
296 | fb_info.pseudo_palette = pseudo_palette; | |
297 | fb_info.flags = FBINFO_DEFAULT; | |
298 | ||
299 | /* Clear the framebuffer */ | |
300 | memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len); | |
301 | udelay(200); | |
302 | ||
303 | fb_alloc_cmap(&info->cmap, size, 0); | |
304 | ||
305 | if (register_framebuffer(&fb_info) < 0) | |
306 | return -1; | |
307 | ||
308 | printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n", | |
309 | fb_info.node, (u_int) (fb_info.fix.smem_len >> 10)); | |
310 | return 0; | |
311 | } | |
312 | ||
313 | int __init tx3912fb_setup(char *options) | |
314 | { | |
315 | char *this_opt; | |
316 | ||
317 | if (!options || !*options) | |
318 | return 0; | |
319 | ||
320 | while ((this_opt = strsep(&options, ","))) { | |
321 | if (!strncmp(options, "bpp:", 4)) | |
322 | tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0); | |
323 | } | |
324 | return 0; | |
325 | } | |
326 | ||
327 | module_init(tx3912fb_init); | |
328 | MODULE_LICENSE("GPL"); |